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?
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 Bard, it explains:"In Go, objects that are in a cyclic structure and that are marked with a finalizer (with SetFinalizer) don't get garbage collected when there are no more live pointers to the cyclic structure because the garbage collector cannot determine a safe order to run the finalizers.
"Which seems to match the Boehm collector explanation, described under "Topologically Ordered Finalization".