Question to GC experts: NO_SCAN for a part of the block
ag0aep6g via Digitalmars-d
digitalmars-d at puremagic.com
Sun Jun 4 02:38:45 PDT 2017
On 06/04/2017 03:08 AM, Stanislav Blinov wrote:
> ---
>
> import core.memory : GC;
> import std.stdio;
> import std.typecons;
>
> class C {
> int i;
> this(int i) {
> this.i = i;
> }
>
> ~this() {
> writeln("C(", i, ") dtor");
> }
> }
[...]
> auto selective(int numCs, int numBytes) {
[...]
> auto memory = GC.malloc(numCs*C.sizeof + numBytes*byte.sizeof,
> GC.BlkAttr.NO_SCAN);
> auto cs = (cast(C*)memory)[0..numCs];
> cs[] = C.init;
> // add scanning range for references
> GC.addRange(cs.ptr, cs.length*C.sizeof, typeid(C));
> auto bytes = (cast(byte*)(memory + numCs*C.sizeof))[0..numBytes];
> bytes[] = byte.init;
> return tuple!("Cs", "bytes")(cs, bytes);
> }
>
> void main() {
>
> int numCs = 4; // comes at runtime from elsewhere
> int numBytes = 32; // comes at runtime from elsewhere
[...]
> int counter;
[...]
> auto arrays3 = selective(numCs, numBytes);
> foreach (ref e; arrays3.Cs)
> e = new C(counter++); // dtors will not be called
> }
>
> ---
>
> Should this work, and if not, why?
As far as I can tell, the `addRange` call works correctly, but maybe too
well in a sense. It keeps the `new`ed `C`s alive as long as `arrays3.Cs`
has pointers to them. And `arrays3.Cs` has those pointers until the very
end.
If you add `GC.removeRange(arrays3.Cs.ptr);` at the of `main`, the dtors
show up. Overwriting `arrays3.Cs`'s elements with `null`s also works. My
guess is that the `removeRange` call isn't done automatically before the
final run of the GC. Maybe it should be?
But I have a vague memory that the GC isn't required to call destructors
on everything in the final run. Or maybe it's not guaranteed that there
is a final run when the program ends? Anyway, that would mean
everything's working as intended, and you just can't rely on destructors
like that.
More information about the Digitalmars-d
mailing list