Don't Fear the Reaper



D, like many languages ​​in use today, comes with a Garbage Collector (GC). Many types of software can be developed without thinking about GC at all, taking full advantage of its advantages. However, the GC has its flaws, and in some scenarios garbage collection is undesirable. For such cases, the language allows you to temporarily disable the garbage collector, or even do without it altogether.



To get the most out of the garbage collector and minimize its drawbacks, you need to have a good understanding of how GC works in D language. A good place to start is the Garbage Collection page on dlang.org , which provides a rationale for GC in D and provides a few tips on how to work with him. This is the first in a series of articles to cover the topic in more detail.



This time we will touch only on the very basics, focusing on the functions of the language that can cause memory allocation through the GC. Future articles will present ways to disable GC if necessary, as well as idioms to help deal with its non-determinism (for example, resource management in object destructors controlled by GC).



The very first thing to understand is that D's garbage collector is only triggered during memory allocation and only if there is no memory to allocate. He does not sit in the background, periodically scanning the pile and collecting trash. You need to understand this in order to write GC-controlled memory efficient code. Consider the following example:



void main() {
    int[] ints;
    foreach(i; 0..100) {
        ints ~= i;
    }
}


This program creates a dynamic array of type values int, and then uses the join operator in D to add numbers from 0 to 99 to it foreach. What is not obvious to the untrained eye is that the join operator allocates memory for added values ​​through the garbage collector.



D . , . , , . , , capacity. , , .



void main() {
    import std.stdio : writefln;
    int[] ints;
    size_t before, after;
    foreach(i; 0..100) {
        before = ints.capacity;
        ints ~= i;
        after = ints.capacity;
        if(before != after) {
            writefln("Before: %s After: %s",
                before, after);
        }
    }
}


DMD 2.073.2,  β€” GC. , GC . . , GC, .



, before after. : 0, 3, 7, 15, 31, 63, 127. ints 100 , 27 , , 255, . , , D, . , GC , (Steve Schveighoffer) .



, , GC . , , «» . GC .



, C C++, , . ,  β€” , . , GC D , . :



void main() {
    int[] ints = new int[](100);
    foreach(i; 0..100) {
        ints[i] = i;
    }
}


. , β€” . 100 . new 100, .



: reserve:



void main() {
    int[] ints;
    ints.reserve(100);
    foreach(i; 0..100) {
        ints ~= i;
    }
}


100 , ( length 0), . , 100 , , .



new reserve, , GC.malloc.



import core.memory;
void* intsPtr = GC.malloc(int.sizeof * 100);
auto ints = (cast(int*)intsPtr)[0 .. 100];


.



auto ints = [0, 1, 2];


, enum.



enum intsLiteral = [0, 1, 2];
auto ints1 = intsLiteral;
auto ints2 = intsLiteral;


enum .  β€” . , . ints1, ints2 , :



auto ints1 = [0, 1, 2];
auto ints2 = [0, 1, 2];


, . , ( D β€” ) β€” .



int[3] noAlloc1 = [0, 1, 2];
auto noAlloc2 = "No Allocation!";


:



auto a1 = [0, 1, 2];
auto a2 = [3, 4, 5];
auto a3 = a1 ~ a2;


D , , . : keys values, . , , - ,  β€” . , GC.



- , , , . , . , . D : byKey, byValue byKeyValue. , . , , . Ranges More Range (Ali Γ‡ehreli) Programming in D.



 β€” ,  β€” . , Garbage Collection β€” assert. , assert , AssertError, D, ( , GC).



, Phobos β€” D. - - Phobos’ GC, , . , Phobos GC. , , , , , . GC (, , ,  β€” - ).



Now that we've got a grasp of the basics of working with GC, in the next article in this series we'll see what tools in the language and compiler will allow us to disable the garbage collector and ensure that critical areas of the program don't access the GC.



Thanks to Guillaume Piolat and Steve Schweihoffer for their help in preparing this article.




All Articles