How to destruct class instances allocated by a Region-allocator over a single GC block

Per Nordlöw per.nordlow at gmail.com
Mon Apr 2 14:52:34 UTC 2018


As a follow-up to

https://forum.dlang.org/post/jfgpngdudtprzznrckwf@forum.dlang.org

I managed to put together the benchmark

https://github.com/nordlow/phobos-next/blob/fa3526b15c746bda50a195f4e492ab2de9c15287/benchmarks/allocators/source/app.d

which run (via ldc)

dub run --build=release-nobounds

prints

DoubleNode Region allocator: 103 ms and 810 μs
DoubleNode new-allocation: 2 secs, 565 ms, and 566 μs
DoubleNode with global allocator: 2 secs, 680 ms, and 93 μs
...

proving the massive speedups possible when using, for instance, a 
Region allocator over a single continuous memory block, in this 
case allocated by the GC.

The code tested is in essence the performance of 10 million 
consecutive calls to the factory function `make` constructing 
instances of the class `DoubleNode`:

void benchmarkAllocatorsRegion()
{
     immutable nodeCount = 10_000_000; // number of `Nodes`s to 
allocate

     void[] buf = GCAllocator.instance.allocate(nodeCount * 
__traits(classInstanceSize, DoubleNode));
     auto allocator = Region!(NullAllocator, 
platformAlignment)(cast(ubyte[])buf);

     Type make(Type, Args...)(Args args) // TODO this should be 
pure
     {
         pragma(inline, true);
         return allocator.make!Type(args);
     }

     void[] allocate(size_t bytes)
     {
         return allocator.allocate(bytes); // TODO should be @safe 
pure
     }

     /* latest pointer here to prevent fast scoped non-GC 
allocation in LDC */
     void* latestPtr;

     void testRegionAllocator()
     {
         auto x = make!DoubleNode(42);
         assert(x);
         latestPtr = cast(void*)x;
     }

     void testNewAllocation()
     {
         auto x = new DoubleNode(42);
         latestPtr = cast(void*)x;
     }

     void testGlobalAllocator()
     {
         auto x = theAllocator.make!DoubleNode(42);
         latestPtr = cast(void*)x;
     }

     const results = benchmark!(testRegionAllocator,
                                testNewAllocation,
                                testGlobalAllocator)(nodeCount);
     writeln("DoubleNode Region allocator: ", results[0]);
     writeln("DoubleNode new-allocation: ", results[1]);
     writeln("DoubleNode with global allocator: ", results[2]);
}

However, I can't figure out how we can be sure that the 
destructors of `DoubleNode` are called for all the 10 million 
objects. Is there a way to tell the GC where the class instances 
that need to be destroyed lie (when nothing references them 
anymore).


More information about the Digitalmars-d-learn mailing list