// D is a system language so its memory management is refined. // D supports thread-local memory on default, global memory, memory // allocated on the stack, the C heap, or the D heap managed by a // garbage collector, both manually and automatically. // This program looks scary because its purpose is to show all the // variety. But lot of this stuff is only for special situations // (like alloca), and it's not necessary in most user code. enum int nInts = 10; // Compile-time constant. // This is thread-local: int[nInts] data1; // This is global: __gshared int[nInts] data2; void main() { // Static memory, it's thread-local but its name is usable // only locally: static int[nInts] data3; // Static memory, it's global but its name is usable only locally: __gshared static int[nInts] data4; // ---------------------- // D supports the functions that manage memory of the C heap: import core.stdc.stdlib: malloc, calloc, realloc, free, alloca; // Allocates space for some integers on the heap, // the memory is not initialized: auto ptr1 = cast(int*)malloc(nInts * int.sizeof); if (ptr1 == null) return; // Increases the space for one more integer, the new space // is not initialized, but the old space is not modified: ptr1 = cast(int*)realloc(ptr1, (nInts + 1) * int.sizeof); if (ptr1 == null) return; // calloc allocates on the heap and zeros the memory: auto ptr2 = cast(int*)calloc(nInts, int.sizeof); if (ptr2 == null) return; // You can create a slice from a pointer: auto slice1 = ptr2[0 .. nInts]; // Frees the memory: free(ptr2); free(ptr1); // ---------------------- import core.stdc.stdio: puts; static struct Test { ~this() { puts("Test destructor"); } } // Memory allocated on the stack: Test[2] array1; { // More memory allocated on the stack: Test[2] array2; // Here array2 is removed from the stack, // and all array2 destructors get called. } puts("Block end."); // alloca is supported in D. It's similar to malloc but the // memory is allocated on the stack: int* ptr3 = cast(int*)alloca(nInts * int.sizeof); // You can create a slice from the pointer: auto slice2 = ptr3[0 .. nInts]; // Do not free the memory allocated with alloca: // free(ptr3); // ---------------------- // Allocates a dynamic array on the D heap managed by // the D garbage collector: auto array3 = new int[nInts]; // Try to reserve capacity for a dynamic array on the D heap: int[] array4; array4.reserve(nInts); assert(array4.capacity >= nInts); assert(array4.length == 0); // Appends one integer to the dynamic array: array4 ~= 100; // Assume that it is safe to append to this array. Appends made // to this array after calling this function may append in place, // even if the array was a slice of a larger array to begin with: array4.assumeSafeAppend; array4 ~= 200; array4 ~= 300; assert(array4.length == 3); // See here for more info: // http://dlang.org/d-array-article.html // Allocates a struct and a class on the D GC heap: static class Foo { int x; } Test* t = new Test; // This destructor will not be called. Foo f1 = new Foo; // f1 is a class reference. // Optional. Destroys the given object and puts it in // an invalid state: f1.destroy; import std.typecons: scoped; // Allocates a class on the stack, unsafe: auto f3 = scoped!Foo(); // ---------------------- import core.memory: GC; // Allocates an aligned block from the GC, initialized to zero. // Plus it doesn't scan through this block on collect. auto ptr4 = cast(int*)GC.calloc(nInts * int.sizeof, GC.BlkAttr.NO_SCAN); // No need to test for this, because GC.calloc usually // throws OutOfMemoryError if it can't allocate. // if (ptr4 == null) // exit(1); GC.free(ptr4); // This is optional. }