Explicitly avoid GC of objects?

Johan Engelen j at j.nl
Tue May 21 22:16:31 UTC 2019


On Tuesday, 21 May 2019 at 13:23:54 UTC, Benjamin Schaaf wrote:
> On Tuesday, 21 May 2019 at 11:54:08 UTC, Robert M. Münch wrote:
>> Is there a trick to accomplish 2 when objects are created from 
>> different scopes which need to be kept? So, I have one 
>> function creating the objects and one using them. How can I 
>> keep things on the stack between these two functions?
>>
>> How is 3 done? Is this only useful for static variables?
>
> I'll try to describe rules 2 and 3 as simply as possible: As 
> long as you can access the pointer to gc allocated memory in D 
> it will not be freed.

If you don't actually access the pointer, the compiler may 
optimize-out storage of that pointer and the garbage collector 
will then not see it. So this statement should read: "As long as 
_the GC_ can see the pointer to gc allocated memory in D it will 
not be freed". The GC is looking at registers, stack, static 
memory, GC allocated memory, ...

> So whether that pointer lives on the stack:
>
> int* foo() {
>     return new int;
> }
> void bar() {
>     int* a = foo();
>     c_fn(a);
> }

This is actually not GC safe [*]. The local storage `a` is 
optimized out, and the parameter to `c_fn` is passed in a 
register is not guaranteed to not be overwritten by `c_fn`. If 
after the overwrite, the GC is invoked (e.g. from other thread, 
or from deeper call tree in `c_fn`) then the memory may be freed.
LDC, DMD, GDC, all 3 perform that optimization. So more care is 
needed here!
https://d.godbolt.org/z/DumVNF

> In static or thread local memory:
>
> int* a;
> __gshared int* b;
> void bar() {
>     a = new int;
>     c_fn(a);
>     b = a;
>     c_fn(b);
> }

Also here, whole-program analysis/optimization may discover that 
`a` and `b` are really never used by anyone. Again, 
optimizing-out those storage spaces will make this code GC unsafe 
[*]. In this case, I think LTO and LTO visibility of the c_fn 
implementation would be needed to do that optimization and thus 
probably will be safe, for now (!).

-Johan

[*] The unsafety is a little tricky. If `c_fn` stores the pointer 
in a place where the GC can see it (registers, D static memory, 
...) all is good. But if `c_fn` stores it in, say, a variable on 
the C side, removes it from register, and _then_ GC is invoked, 
that's when trouble may happen.




More information about the Digitalmars-d-learn mailing list