How to make this simple circular reference collected?
thautwarm opened this issue · comments
MWE here: https://github.com/thautwarm/dotnet-bdwgc/blob/main/deps/mwe.c
- OS: Windows 11
- C Compiler: gcc version 13.2.0 (Rev2, Built by MSYS2 project) Target: x86_64-w64-mingw32
- bdwgc build options:
-DENABLE_DISCLAIM
-DGC_ATOMIC_UNCOLLECTABLE
-DGC_GCJ_SUPPORT
-DJAVA_FINALIZATION
-DNO_EXECUTE_PERMISSION
-DUSE_MMAP
-DUSE_MUNMAP
-DGC_THREADS
-DPARALLEL_MARK
-DTHREAD_LOCAL_ALLOC
Basically I want to make the following code collected, but it didn't.
void test()
{
struct S* s = (struct S*) GC_malloc(sizeof(struct S));
// EDIT: changing `s->self = NULL` to `s->self = s`
// OP writes `s->self = NULL` then `s` is not a circular reference
s->self = s;
GC_register_finalizer(s, finalizer, NULL, NULL, NULL);
}
int main()
{
for(int i = 0; i < 10000; i++)
test();
GC_gcollect();
printf("done\n");
}
Sorry, I can't reproduce such behavior:
test581.c:
#include "gc.h"
void finalizer(void *obj, void *client_data)
{
}
struct S { void *self; };
void test()
{
struct S* s = (struct S*) GC_malloc(sizeof(struct S));
GC_register_finalizer(s, finalizer, NULL, NULL, NULL);
}
int main()
{
for(int i = 0; i < 10000; i++)
test();
GC_gcollect();
GC_gcollect();
GC_gcollect();
}
set path=C:\msys64\mingw64\bin
gcc -I include -I libatomic_ops/src -DENABLE_DISCLAIM -DGC_ATOMIC_UNCOLLECTABLE -DGC_GCJ_SUPPORT -DJAVA_FINALIZATION -DNO_EXECUTE_PERMISSION -DUSE_MMAP -DUSE_MUNMAP -DGC_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC test581.c extra/gc.c
set GC_PRINT_STATS=1
a.exe
a.gc.log content (tail):
--> Marking for collection #12 after 69280 allocated bytes
World-stopped marking took 0 ms 0 ns (1 ms in average)
GC #12 freed 35520 bytes, heap 128 KiB (+ 0 KiB unmapped + 426 KiB internal)
In-use heap: 0% (84 KiB pointers + 68 KiB other)
1 finalization entries; 0/0 short/long disappearing links alive
1076 finalization-ready objects; 0/0 short/long links cleared
Finalize and initiate sweep took 0 ms 0 ns + 0 ms 0 ns
Complete collection took 16 ms 0 ns
Initiating full world-stop collection!
--> Marking for collection #13 after 0 allocated bytes
World-stopped marking took 15 ms 0 ns (2 ms in average)
GC #13 freed 69632 bytes, heap 128 KiB (+ 0 KiB unmapped + 426 KiB internal)
In-use heap: 12% (17 KiB pointers + 0 KiB other)
1 finalization entries; 0/0 short/long disappearing links alive
0 finalization-ready objects; 0/0 short/long links cleared
Finalize and initiate sweep took 0 ms 0 ns + 0 ms 0 ns
Complete collection took 15 ms 0 ns
Initiating full world-stop collection!
--> Marking for collection #14 after 0 allocated bytes
World-stopped marking took 0 ms 0 ns (2 ms in average)
GC #14 freed 0 bytes, heap 128 KiB (+ 0 KiB unmapped + 426 KiB internal)
In-use heap: 12% (17 KiB pointers + 0 KiB other)
1 finalization entries; 0/0 short/long disappearing links alive
0 finalization-ready objects; 0/0 short/long links cleared
Finalize and initiate sweep took 0 ms 0 ns + 0 ms 0 ns
Complete collection took 0 ms 0 ns
You cant see that almost all finalizable objects are freed.
Sorry, I made a mistake in the definition of the test
function, it should be:
void test()
{
struct S* s = (struct S*) GC_malloc(sizeof(struct S));
s->self = s; // this is the key point
GC_register_finalizer(s, finalizer, NULL, NULL, NULL);
}
I tried changing the build options, then I got a .log file which has a lot of lines similar to the following:
GC Warning: Finalization cycle involving 00000297bcc10420
Does this mean that the circular references are handled, but finalization for circular references are not supported tho?
I finally find the related words from the docs.
If in the process of marking from an object the object itself becomes marked,
we have uncovered a cycle involving the object. This usually results in
a warning from the collector. Such objects are not finalized, since it may be
unsafe to do so. See the more detailed discussion of
finalization semantics.
Yes, use GC_register_finalizer_ignore_self or ..._no_order.