RosettaCodeData/Task/Memory-allocation/D/memory-allocation.d

136 lines
4.0 KiB
D

// 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.
}