D, como muchos idiomas que se usan ampliamente hoy en día, viene con un recolector de basura (GC). Se pueden desarrollar muchos tipos de software sin pensar en GC, aprovechando al máximo sus ventajas. Sin embargo, el GC tiene sus defectos, y en algunos escenarios la recolección de basura no es deseable. Para tales casos, el idioma le permite deshabilitar temporalmente el recolector de basura o incluso prescindir completamente de él.
Para aprovechar al máximo el recolector de basura y minimizar sus inconvenientes, debe tener una buena comprensión de cómo funciona GC en lenguaje D. Un buen lugar para comenzar es la página de Recolección de basura en dlang.org , que proporciona una justificación para GC en D y proporciona algunos consejos sobre cómo trabajar con él. Este es el primero de una serie de artículos que cubre el tema con más detalle.
Esta vez solo tocaremos los conceptos básicos, enfocándonos en las funciones del lenguaje que pueden causar la asignación de memoria a través del GC. Los artículos futuros presentarán formas de deshabilitar GC cuando sea necesario, así como expresiones idiomáticas para ayudar a lidiar con su no determinismo (por ejemplo, gestión de recursos en destructores de objetos bajo control GC).
Lo primero que hay que entender es que el recolector de basura de D solo se ejecuta durante la asignación de memoria y solo si no hay memoria para asignar. No se sienta en el fondo, escanea periódicamente la pila y recoge la basura. Esto debe entenderse para escribir código que efectivamente use memoria bajo el control del GC. Considere el siguiente ejemplo:
void main() {
int[] ints;
foreach(i; 0..100) {
ints ~= i;
}
}
Este programa crea una matriz dinámica de valores de tipo int
y luego usa el operador de unión en D para agregarle números del 0 al 99 foreach
. Lo que no es obvio para el ojo inexperto es que el operador de unión asigna memoria para valores agregados a través del recolector de basura.
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];
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 (, , , — - ).
Ahora que conocemos los conceptos básicos de trabajar con GC, en el próximo artículo de esta serie veremos qué herramientas en el lenguaje y el compilador nos permitirán desactivar el recolector de basura y garantizar que las áreas críticas del programa no accedan al GC.
Gracias a Guillaume Piolat y Steve Schweichoffer por su ayuda en la preparación de este artículo.