La vida en el carril rápido

Serie GC


En el primero de una serie sobre GC, presenté el recolector de basura D y las características del lenguaje que lo usan. Dos puntos clave que intenté transmitir:



  1. GC solo se ejecuta cuando solicita una asignación de memoria . Contrariamente a la idea errónea popular, el lenguaje D GC no puede simplemente pausar y pausar su clon de Minecraft en medio de un ciclo de juego. Solo se ejecuta cuando solicita memoria a través de él y solo cuando es necesario.



  2. Las estrategias simples de asignación de memoria de estilo C y C ++ pueden reducir la carga en el GC . No asigne memoria dentro de bucles; en su lugar, preasigne tantos recursos como sea posible o use la pila. Minimice el número total de asignaciones de memoria a través del GC. Estas estrategias funcionan debido al n. ° 1. El desarrollador puede dictar cuándo ejecutar la recolección de basura mediante el uso inteligente de la asignación de almacenamiento dinámico administrada por GC.





Las estrategias del punto # 2 están bien para el código que el programador escribe él mismo, pero no son particularmente útiles cuando se trata de bibliotecas de terceros. En estos casos, utilizando los mecanismos del lenguaje D y su tiempo de ejecución, puede asegurarse de que no se produzca asignación de memoria en puntos críticos del código. También hay opciones de línea de comandos para ayudar a garantizar que GC no se interponga en su camino.



Imaginemos que está escribiendo un programa D y por una razón u otra decidió eliminar la recolección de basura por completo. Tienes dos soluciones obvias.



Píldora para la codicia



La primera solución es llamar GC.disablecuando se inicia el programa. La asignación de memoria a través de GC seguirá funcionando, pero se detendrá la recolección de basura. Toda la recolección de basura, incluido lo que pudo haber sucedido en otros subprocesos.



void main() {
    import core.memory;
    import std.stdio;
    GC.disable;
    writeln("Goodbye, GC!");
}


Salida:



Goodbye, GC!


, , GC, , . , , , . , - . :



, , .

, . , - , . GC.enable GC.collect. , C C++.





, @nogc. main, .



@nogc
void main() { ... }


GC. @nogc, main, , . « ».



, GC.disable. .



@nogc
void main() {
    import std.stdio;
    writeln("GC be gone!");
}


:



Error: @nogc function 'D main' cannot call non-@nogc function 'std.stdio.writeln!string.writeln'
(: @nogc- 'D main'    -@nogc– 'std.stdio.writeln!string.writeln')


@nogc , . . @nogc, , , @nogc. , writeln .



:



@nogc 
void main() {
    auto ints = new int[](100);
}


:



Error: cannot use 'new' in @nogc function 'D main'
(:   'new'  @nogc- 'D main')


@nogc- , GC ( ). . , , GC . , , @nogc, .



, @nogc , . , , - ( ). — . :



throw new Exception("Blah");


- , new, @nogc- . , , , - , … , . D , , throw new Exception GC, .



, @nogc- . (. .)

@nogc main — , .



, : @nogc main GC . D . main, — . @nogc, , , GC @nogc-. , @nogc, main, , main , , GC.





. , D, GC . , GC — . , , D: GC . , , .



, , , GC. @nogc / API core.memory.GC . @nogc main, , GC. GC.disable . , GC.enable. , GC (, ), GC.collect.



, , , . API core.memory.GC GC . D.



( !) D --DRT-gcopt=profile:1, . GC, , .



: gcstat.d .



void main() {
    import std.stdio;
    int[] ints;
    foreach(i; 0 .. 20) {
        ints ~= i;
    }
    writeln(ints);
}


GC:



dmd gcstat.d
gcstat --DRT-gcopt=profile:1
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
        Number of collections:  1
        Total GC prep time:  0 milliseconds
        Total mark time:  0 milliseconds
        Total sweep time:  0 milliseconds
        Total page recovery time:  0 milliseconds
        Max Pause Time:  0 milliseconds
        Grand total GC time:  0 milliseconds
GC summary:    1 MB,    1 GC    0 ms, Pauses    0 ms <    0 ms


, , , . D GC , ( ) . , , D , GC - ( ).



DMD -vgc, GC — , , ~=.



: inner.d.



void printInts(int[] delegate() dg)
{
    import std.stdio;
    foreach(i; dg()) writeln(i);
} 

void main() {
    int[] ints;
    auto makeInts() {
        foreach(i; 0 .. 20) {
            ints ~= i;
        }
        return ints;
    }

    printInts(&makeInts);
}


makeInts — . , , / ( static, delegate function). .



-vgc:



dmd -vgc inner.d
inner.d(11): vgc: operator ~= may cause GC allocation
inner.d(7): vgc: using closure causes GC allocation

(inner.d(11): vgc:  ~=      GC)
(inner.d(7): vgc:        GC)


, , ints, ( — - delegate). ints makeInts . , - . printInts :



void printInts(scope int[] delegate() dg)


scope , . , dg . , . . , , .





, GC D , Java C#, . , D , Java, . , D. , Java, GC , .



, , , , . D № 2 , @nogc core.memory.GC , . , , , .



, D. , Phobos — D — @nogc. , , .



En futuros artículos, veremos cómo asignar memoria sin recurrir al GC y usarla en paralelo con la memoria del GC, en lugar de reemplazar las @nogccaracterísticas del lenguaje que no están disponibles en el código, y mucho más.



Gracias a Vladimir Panteleev, Guillaume Piolat y Steven Schveighoffer por sus valiosos comentarios sobre el borrador de este artículo.




All Articles