La vie Ă  vitesse grand V



Dans le premier d'une série sur GC, j'ai présenté le garbage collector D et les fonctionnalités de langage qui l'utilisent. Deux points clés que j'ai essayé de transmettre:



  1. GC ne s'exécute que lorsque vous demandez une allocation de mémoire . Contrairement à une idée fausse populaire, le GC en langage D ne peut pas simplement mettre en pause et mettre en pause votre clone Minecraft au milieu d'une boucle de jeu. Il ne s'exécute que lorsque vous demandez de la mémoire via lui et uniquement en cas de besoin.



  2. Des stratégies d'allocation de mémoire de style C et C ++ simples peuvent réduire la charge sur le GC . N'allouez pas de mémoire à l'intérieur des boucles - à la place, pré-allouez autant de ressources que possible ou utilisez la pile. Réduisez le nombre total d'allocations de mémoire via le GC. Ces stratégies fonctionnent grâce à # 1. Le développeur peut dicter quand exécuter le garbage collection en utilisant intelligemment l'allocation de tas gérée par GC.





Les stratégies du point n ° 2 conviennent pour le code que le programmeur écrit lui-même, mais elles ne sont pas particulièrement utiles lorsqu'il s'agit de bibliothèques tierces. Dans ces cas, en utilisant les mécanismes du langage D et de son exécution, vous pouvez vous assurer qu'aucune allocation de mémoire ne se produit à des points critiques du code. Il existe également des options de ligne de commande pour vous assurer que GC ne vous gêne pas.



Imaginons que vous écriviez un programme D et que, pour une raison ou une autre, vous ayez décidé d'éliminer complètement le garbage collection. Vous avez deux solutions évidentes.



Pilule pour la cupidité



La première solution consiste à appeler GC.disablelorsque le programme démarre. L'allocation de mémoire via GC fonctionnera toujours, mais le garbage collection s'arrêtera. Tous les garbage collection, y compris ce qui s'est passé sur d'autres threads.



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


Production:



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



Dans les prochains articles, nous verrons comment allouer de la mémoire sans recourir à GC, et l'utiliser en parallèle avec la mémoire du GC, puis remplacer les @nogcfonctionnalités de langage qui ne sont pas disponibles dans le code, et bien plus encore.



Merci à Vladimir Panteleev, Guillaume Piolat et Steven Schveighoffer pour leurs précieux commentaires sur le projet de cet article.




All Articles