Alternative Memory Management in D

Reaching C++ level of abstraction

D is not Java or C#. Being a system language, it lets you do anything that you can do with C or C++. You can allocate memory by any available means, including GC, C-style malloc, external library, or a custom allocator. Thanks to powerful metaprogramming capabilities, D allows to hide an ugly allocation mechanism under a simple API. One such API is implemented in dlib — it provides New and Delete functions that wrap malloc and free. They are similar to new and delete operators in C++ — they allocate and free arrays, classes and structs, properly initializing them and calling constructors when necessary:

import dlib.core.memory;void main()
{
int[] array = New!(int[])(100);
Delete(array);

MyClass obj = New!MyClass(1, 2, 3);
Delete(obj);
}

Allocators

New is not just a syntactic sugar. Under the hood it is powered by abstract allocators from dlib.memory. Allocators are objects that implement a simple memory consumption interface (see dlib.memory.allocator). You can create your own allocator and replace dlib’s default one with it. Because allocator can allocate itself, it is rather simple. There are several alternative allocators in dlib, including GC-based one:

import dlib.core.memory;
import dlib.memory.gcallocator;
void main()
{
Allocator defaultAllocator = globalAllocator;
globalAllocator = GCallocator.instance;
// ‘New’ will use GCallocator

globalAllocator = defaultAllocator;
// ‘New’ will again use default allocator based on malloc
}

Ownership

Plain New and Delete may be enough for many simple cases, but if you’re writing an application with lots of objects things can quickly become complicated. The memory may end up leaking if you forget to delete some object, and bugs like that are not the easiest to fix. Garbage collection is there to solve this problem, but it brings plenty of other issues, so dlib provides an alternative — object ownership.

import dlib.core.memory;
import dlib.core.ownership;
class MyClass: Owner
{
this(Owner owner = null)
{
super(owner);
}
}
void main()
{
MyClass c1 = New!MyClass();
MyClass c2 = New!MyClass(c1);
Delete(c1); // c2 is deleted automatically
}
class MyClass: Owner
{
//...
~this()
{
Delete(myArray);
free(myExternalData);
}
}

Conclusion

D’s native memory management with GC
Pros: easiest to use, part of the language syntax.
Cons: unpredictable, requires additional logic to correctly handle external resources, still can cause memory leaks if used carelessly.
Summary: best suited for applications that constantly allocate short-living objects, or for utilities that perform one task and then exit. Not suitable for game engines that work heavily with VRAM data, which cannot be managed with GC.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store