That makes sense that if you have only one finalizer in the cycle, the
ordering could be respected, thanks for pointing it out!
Now I still don't understand your explanation. The fact that the cycles can
be arbitrarily deep is the same for normal GC, and it works without an
issue. But I don't
On Tuesday, November 7, 2023 at 2:32:28 AM UTC-5 Jan wrote:
Btw, I don't follow the sentence:
"the GC necessarily has to keep referents of the object-to-be-finalized
live even if the object isn't referenced anymore"
That is true for objects not in cycles that need to be finalized as well.
I can completely understand the logic behind not freeing the objects with
unclear ordering. But I expected that there will be some kind of upper
limit / workaround for these kind of objects. But this means that using
SetFinalizer on a big object, carelessly, can potentially lead to memory
Btw, I don't follow the sentence:
"the GC necessarily has to keep referents of the object-to-be-finalized
live even if the object isn't referenced anymore"
That is true for objects not in cycles that need to be finalized as well.
I'm not sure I follow the reasoning here ...
Asking about it in
Yes, cycles containing a finalizer aren't guaranteed to be freed. As others
have pointed out, this is documented. SetFinalizer is really designed for a
narrow set of use-cases, so concessions were made for overall GC
performance. This case is one of them.
IIUC, the core problem is a
Does this behaviour mean that, those memory will never be freed and keep
piling on ? That can be disastrous.
On Monday, November 6, 2023 at 3:39:50 PM UTC+5:30 Jan wrote:
> For what it's worth, a bit of "memory management" on structures in many
> cases is very ok (not sure if in your case). So
For what it's worth, a bit of "memory management" on structures in many
cases is very ok (not sure if in your case). So for your cyclic structure
with finalizers, requiring the user of your code to call some "Finalize()"
method (some destructor method you define) that manually breaks the cycle,
I was very surprised by this behavior of SetFinalizer: and indeed if you
remove the SetFinalizer one can see that s1 is freed, because the memory
reported by `m.HeapAlloc` goes back down.
I think you already have the answer: the block that has the cycle (s1 and
s2) have a SetFinalizer set, and
Just my(newbie of GC) guess:
In the mark stage,
- GC find s1's finalizer and invoke scanobject to scan s1
https://github.com/golang/go/blob/go1.21.1/src/runtime/mgcmark.go#L391
https://github.com/golang/go/blob/go1.21.1/src/runtime/mfinal.go#L484
- then find s2 and queue it to be scanned
-