Vida na pista rápida



Na primeira de uma série no GC, apresentei o coletor de lixo D e os recursos de idioma que o utilizam. Dois pontos-chave que tentei transmitir:



  1. O GC é executado somente quando você solicita uma alocação de memória . Ao contrário do equívoco popular, o GC da linguagem D não pode simplesmente pausar e pausar seu clone do Minecraft no meio de um ciclo de jogo. Só é executado quando você solicita memória através dele e somente quando necessário.



  2. Estratégias simples de alocação de memória no estilo C e C ++ podem reduzir a carga no GC . Não aloque memória dentro de loops - em vez disso, pré-aloque o máximo de recursos possível ou use a pilha. Minimize o número total de alocações de memória através do GC. Essas estratégias funcionam por causa do nº 1. O desenvolvedor pode determinar quando executar a coleta de lixo usando inteligentemente a alocação de heap gerenciada por GC.





As estratégias do ponto 2 são adequadas para o código que o programador escreve, mas não são particularmente úteis quando se trata de bibliotecas de terceiros. Nesses casos, usando os mecanismos da linguagem D e seu tempo de execução, você pode garantir que nenhuma alocação de memória ocorra em pontos críticos do código. Também existem opções de linha de comando para ajudar a garantir que o GC não atrapalhe.



Vamos imaginar que você esteja escrevendo um programa em D e, por um motivo ou outro, resolva eliminar completamente a coleta de lixo. Você tem duas soluções óbvias.



Comprimido para ganância



A primeira solução é ligar GC.disablequando o programa for iniciado. A alocação de memória via GC ainda funcionará, mas a coleta de lixo será interrompida. Toda a coleta de lixo, incluindo o que pode ter acontecido em outros threads.



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


Resultado:



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. , , .



Em artigos futuros, veremos como alocar memória sem recorrer ao GC e usá-lo em paralelo com a memória do GC, do que substituir os @nogcrecursos de idioma que não estão disponíveis no código e muito mais.



Agradecemos a Vladimir Panteleev, Guillaume Piolat e Steven Schveighoffer por seus valiosos comentários sobre o rascunho deste artigo.




All Articles