GC doesn't collect where expected

Steven Schveighoffer schveiguy at gmail.com
Mon Jun 19 16:43:30 UTC 2023


On 6/19/23 12:13 PM, axricard wrote:
> I'm doing some experiments with ldc2 GC, by instrumenting it and 
> printing basic information (what is allocated and freed)
> 
> My first tests are made on this sample :
> 
> ```
>>> cat test2.d
> import core.memory;
> 
> class Bar { int bar; }
> 
> class Foo {
> 
>    this()
>    {
>      this.bar = new Bar;
>    }
> 
>    Bar bar;
> }
> 
> 
> void func()
> {
>    Foo f2 = new Foo;
> }
> 
> int main()
> {
>    Foo f = new Foo;
> 
>    func();
>    GC.collect();
> 
>    return 0;
> }
> 
> ```
> 
> When trying to run the instrumented druntime, I get a strange behavior : 
> the first collection (done with GC.collect) doesn't sweep anything (in 
> particular, it doesn't sweep memory allocated in _func()_). The whole 
> sweeping is done when program finish, at cleanup. I don't understand why 
> : memory allocated in _func()_ shouldn't be accessible from any root at 
> first collection, right ?
> 
> ```
> ╰─> /instrumented-ldc2 -g -O0 test2.d --disable-gc2stack 
> --disable-d-passes --of test2  &&  ./test2 "--DRT-gcopt=cleanup:collect 
> fork:0 parallel:0 verbose:2"
> 
> 
> [test2.d:26] new 'test2.Foo' (24 bytes) => p = 0x7f3a0454d000
> [test2.d:10] new 'test2.Bar' (20 bytes) => p = 0x7f3a0454d020
> [test2.d:21] new 'test2.Foo' (24 bytes) => p = 0x7f3a0454d040
> [test2.d:10] new 'test2.Bar' (20 bytes) => p = 0x7f3a0454d060
> 
> ============ COLLECTION  =============
>          ============= MARKING ==============
>          marking range: [0x7fff22337a60..0x7fff22339000] (0x15a0)
>                  range: [0x7f3a0454d000..0x7f3a0454d020] (0x20)
>                  range: [0x7f3a0454d040..0x7f3a0454d060] (0x20)
>          marking range: [0x7f3a0464d720..0x7f3a0464d8b9] (0x199)
>          marking range: [0x46c610..0x47b3b8] (0xeda8)
>          ============= SWEEPING ==============
> =====================================================
> 
> 
> ============ COLLECTION  =============
>          ============= MARKING ==============
>          marking range: [0x46c610..0x47b3b8] (0xeda8)
>          ============= SWEEPING ==============
>          Freeing test2.Foo (test2.d:26; 24 bytes) (0x7f3a0454d000). AGE 
> :  1/2
>          Freeing test2.Bar (test2.d:10; 20 bytes) (0x7f3a0454d020). AGE 
> :  1/2
>          Freeing test2.Foo (test2.d:21; 24 bytes) (0x7f3a0454d040). AGE 
> :  1/2
>          Freeing test2.Bar (test2.d:10; 20 bytes) (0x7f3a0454d060). AGE 
> :  1/2
> =====================================================
> ```
> 

In general, the language does not guarantee when the GC will collect 
your item.

In this specific case, most likely it's a stale register or stack 
reference. One way I usually use to ensure such things is to call a 
function that destroys the existing stack:

```d
void clobber()
{
    int[2048] x;
}
```

Calling this function will clear out 2048x4 bytes of data to 0 on the stack.

-Steve


More information about the Digitalmars-d-learn mailing list