英文:
Forcing (encouraging) Golang to GC long-lived structures?
问题
我对Golang非常陌生,但对Java和C有很多经验。
我的应用程序有一个相当复杂的、层次化的对象模型,是从数据库中构建的,类似ORM的方式,旨在长期存在。这些结构是使用new和/或make创建的指针构建的。
在某些情况下,我需要将当前的对象从内存中清除,并从数据库重新构建它们。是否可以通过遍历从较低级别开始的结构,并将引用设置为nil,来鼓励Golang回收内存?
有没有更好的方法来做到这一点?
(我开始意识到这种架构实际上并不是Go的典型方式,Go更喜欢将东西保留在堆栈上。然而,我不能自由地放弃它并重新开始,或者改用其他编程语言。)
提前感谢您的任何指导。
英文:
I am very new to Golang, but have lots of Java and C experience.
My application has a fairly complex,hierarchical object model built from a database, ORM-style, which is intended to be long-lived. The structures are built up using pointers created with new and/or make.
There are situations when I need to flush the current objects from memory and rebuild them from the DB. Is it possible to encourage Golang to reclaim the memory by traversing the structures from the lower levels, setting references to nil?
Is there a better way to do this?
(I am starting to realize that this architecture is not really typical for Go, which prefers to keep things on the stack. However, I am not free to discard it and start over, or to change to a different programming language.)
Thanks in advance for any guidance.
答案1
得分: 3
垃圾回收语言的优点在于无需担心内存管理,无需担心内存的分配和释放。
总的原则是:只要某个对象有一个“引用”,它就不会被垃圾回收;而没有任何引用的对象将被垃圾回收。
这个原则当然是“递归”的。如果你有一个指向B
对象的指针的A
对象,并且只有一个对A
的引用(没有其他对B
的引用),一旦该引用“消失”,A
和B
都将被垃圾回收。
因此,如果你想要释放一些复杂的对象层次结构,只需确保不保留指向它的指针,它将自动被释放。你不需要递归地将其指针清零。
但是有一件重要的事情需要记住:**如果你有一个指向对象的“部分”的指针,那么整个对象将保留在内存中。**例如,如果你创建了一个结构体,并且取其中一个字段的地址并将其存储在某个地方,那么该指针将使整个结构体保留在内存中。类似地,如果你创建了一个切片,并且取其中一个元素的地址(并存储它),那么整个切片(或更准确地说是其底层数组)将保留在内存中。如果你重新切片切片以“隐藏”元素,也是如此,例如:
s := make([]*int, 10)
s[8] = new(int)
s = s[:2]
在这里,我们创建了一个包含10个int
指针的切片,我们将一个指针赋值给索引8
,然后将切片重新切片,只保留前两个元素。在后台有一个包含10个指针的底层数组,这个切片操作不会清除它,所以指向的int
(在原始切片的索引8
处)将保留在内存中(只要你有对切片或其底层数组的引用)。详细信息请参见https://stackoverflow.com/questions/28432658/does-go-garbage-collect-parts-of-slices/28432812#28432812
参考相关问题:
https://stackoverflow.com/questions/45509538/freeing-unused-memory/45509642#45509642
英文:
The point of garbage collected languages is that you don't have to worry about memory management, you don't have to worry about memory allocations and deallocations.
The general principle is: as long as you have a "reference" to some object, it will not be garbage collected; and objects that no one has a reference of, will be garbage collected.
This principle is of course "recursive". If you have an A
object holding a pointer to a B
object, and there's only a single reference to A
(and no one else has a reference to B
), once that reference "goes away", both A
and B
will be garbage collected.
So if you want some complex object hierarchy to be freed, just make sure you don't keep pointers to it, and it will be freed automatically. You do not have to traverse it recursively to zero pointers.
There is one important thing to keep in mind though: If you have a pointer to some "part" of an object, that will keep the whole object in memory. For example if you create a struct, and take the address of one of its fields and store it somewhere, that pointer will keep the whole struct in memory. Similarly, if you create a slice and you take the address of one of its elements (and store it), that will keep the whole slice (or more precisely its backing array) in memory. This also applies if you reslice the slice to "hide" elements, e.g.:
s := make([]*int, 10)
s[8] = new(int)
s = s[:2]
Here we created a slice of 10 int
pointers, we assigned a pointer to the index 8
, then resliced the slice to only hold the first 2 elements. There is a backing array in the background with storage for 10 pointers, which is not cleared by the above slicing operation, so the pointed int
(at index 8
in the original slice) will remain in memory (as long as you have a reference to the slice or its backing array). For details, see https://stackoverflow.com/questions/28432658/does-go-garbage-collect-parts-of-slices/28432812#28432812
See related questions:
https://stackoverflow.com/questions/45509538/freeing-unused-memory/45509642#45509642
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论