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 
leaks.

I guess if we provide a destructor( like file.Close() or something like 
that ) for those objects, which just breaks the cycle, it will probably be 
enough to force the GC to clear the memory.

On Tuesday, November 7, 2023 at 8:21:58 AM UTC+5:30 Michael Knyszek wrote:

> 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 combination of the fact that the cycle can be 
> arbitrarily deep and the GC necessarily has to keep referents of the 
> object-to-be-finalized live even if the object isn't referenced anymore. 
> The GC must follow the pointers in an object's referents, and eventually it 
> may come upon the almost-dead object it started from. But at that point it 
> likely has no knowledge of where it came from. It's just a pointer on a 
> queue. A GC could be implemented that keeps track of where the pointers it 
> follows came from, but such an implementation would be substantially less 
> performant.
>
> Other GCs make the same choice. See the Boehm collector 
> <https://www.hboehm.info/gc/finalization.html>, for example.
> On Monday, November 6, 2023 at 10:20:39 AM UTC-5 Harish Ganesan wrote:
>
>> 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 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, 
>>> often is an ok solution. Fundamentally, it's the same as requiring someone 
>>> to call Close() on an opened file (or any other resource, like sockets, db 
>>> connections, etc).
>>>
>>> As an anecdote, previously when I was doing C++ I was a big fan of 
>>> referenced counted smart pointers (`shred_ptr<>`), which gets most of the 
>>> benefit of GC, but with a much lower cost. They required manually breaking 
>>> cycles, which I didn't find to be an issue at all in the great majority of 
>>> the cases.
>>>
>>> On Monday, November 6, 2023 at 11:01:04 AM UTC+1 Jan wrote:
>>>
>>>> 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 it will never run, per documentation 
>>>> (I had never paid attention to this).
>>>>
>>>> A suggestion to work around would be to move the stuff that needs a 
>>>> "Finalizer" to a leaf node, as in:
>>>>
>>>> https://go.dev/play/p/WMMTdAza6aZ
>>>>
>>>> But I understand this is not a solution if the finalizer needs to 
>>>> access the S1 (so, if the finalizer function needs any information that is 
>>>> not self-contained in `S1Data` in my example).
>>>> On Sunday, November 5, 2023 at 4:01:14 PM UTC+1 Soren Yang wrote:
>>>>
>>>>> As shown in the following code:
>>>>>
>>>>> cyclic structure with finalizer <https://go.dev/play/p/Fn_h08y-L6b>
>>>>>
>>>>> The s1 & s2 didn't been free, and finalizer didn't run. But when 
>>>>> enable the line which have been commented, all run as expected(s1 & s2 
>>>>> been 
>>>>> free)。
>>>>>
>>>>> I have seen the comment in runtime.SetFinalizer: If a cyclic 
>>>>> structure includes a block with a finalizer, that cycle is not guaranteed 
>>>>> to be garbage collected and the finalizer is not guaranteed to run, 
>>>>> because 
>>>>> there is no ordering that respects the dependencies.
>>>>>
>>>>> But why it haven't been free in first code?
>>>>>
>>>>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/6dda0d21-bd9f-45eb-bade-f20ac0996f45n%40googlegroups.com.

Reply via email to