www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Dynamic arrays, emplace and GC

reply Claude <no no.no> writes:
Hello,

I've been working on some kind of allocator using a dynamic array 
as a memory pool. I used emplace to allocate class instances 
within that array, and I was surprised to see I had to use 
GC.addRange() to avoid the GC to destroy stuff referenced in that 
array.

Here's a chunk of code[1]:

struct Pool(T)
{
public:
     T alloc(Args...)(Args args)
     {
         mData.length++;
         import core.memory : GC;
         //GC.addRange(mData[$ - 1].data.ptr, mData[$ - 
1].data.length);
         import std.conv : emplace;
         auto t = emplace!T(mData[$ - 1].data, args);
         return t;
     }

private:
     struct Storage
     {
         ubyte[__traits(classInstanceSize, T)] data;
     }

     Storage[] mData;
}

class Foo
{
     this(int a)
     {
         aa = a;
     }
     ~this()
     {
         import std.stdio; writefln("DTOR");
         aa = 0;
     }
     int aa;
}

class Blob
{
     this(int b)
     {
         foo = new Foo(b);
     }

     Foo foo;
}

void main()
{
     Pool!Blob pool;

     Blob blob;
     foreach(a; 0 .. 10000)
     {
         blob = pool.alloc(6);
     }
     while(true){}
     import std.stdio; writefln("END");
}

Basically Blob instances are allocated in the array using 
emplace. And Blob creates references to Foo. If I comment out 
GC.addRange(), I see that Foo destructor is called by the GC[2]. 
If I leave it uncommented, the GC leaves the array alone.

So here's my question: Is it normal???
I thought that allocating memory in a dynamic array using 
"mData.length++;" was GC-compliant (unlike 
core.stdc.stdlib.malloc()), and I did not have to explictly use 
GC.addRange().


[1] I left out alignment management code. It's not the issue here.
[2] I used the helpful destructor tracker function of p0nce 
there: https://p0nce.github.io/d-idioms/#GC-proof-resource-class
Jul 05 2016
parent reply ketmar <ketmar ketmar.no-ip.org> writes:
On Tuesday, 5 July 2016 at 10:04:05 UTC, Claude wrote:
 So here's my question: Is it normal???
yes. `ubyte` arrays by definition cannot hold pointers, so GC doesn't bother to scan 'em.
Jul 05 2016
parent reply Claude <no no.no> writes:
On Tuesday, 5 July 2016 at 12:43:14 UTC, ketmar wrote:
 On Tuesday, 5 July 2016 at 10:04:05 UTC, Claude wrote:
 So here's my question: Is it normal???
yes. `ubyte` arrays by definition cannot hold pointers, so GC doesn't bother to scan 'em.
Ah ok. I tried using void[size] static array and it seems to work without having to use GC.addRange().
Jul 05 2016
parent Rene Zwanenburg <renezwanenburg gmail.com> writes:
On Tuesday, 5 July 2016 at 13:48:46 UTC, Claude wrote:
 Ah ok. I tried using void[size] static array and it seems to 
 work without having to use GC.addRange().
Correct. void[] means the type of the data is unknown, so the GC has to assume it can contain pointers. This also means that _everything_ in any void buffer has to be treated as a potential pointer. In other words, if you allocate a void buffer and fill it with ints, and one of those ints happens to have a value equal to the address of a GC-allocated object, the GC will assume the int is a pointer to that object and not free it.
Jul 05 2016