Leben auf der Überholspur



Im ersten Teil einer Reihe über GC habe ich den D-Garbage-Collector und die Sprachfunktionen vorgestellt, die ihn verwenden. Zwei wichtige Punkte, die ich zu vermitteln versuchte:



  1. GC wird nur ausgeführt, wenn Sie eine Speicherzuordnung anfordern . Im Gegensatz zu weit verbreiteten Missverständnissen kann der D-Sprach-GC Ihren Minecraft-Klon nicht einfach mitten in einer Spielschleife anhalten und anhalten. Es wird nur ausgeführt, wenn Sie Speicher anfordern, und nur bei Bedarf.



  2. Einfache Speicherzuweisungsstrategien im C- und C ++ - Stil können die Belastung des GC verringern . Ordnen Sie keinen Speicher innerhalb von Schleifen zu, sondern weisen Sie stattdessen so viele Ressourcen wie möglich vorab zu oder verwenden Sie den Stapel. Minimieren Sie die Gesamtzahl der Speicherzuordnungen durch den GC. Diese Strategien funktionieren aufgrund von # 1. Der Entwickler kann durch intelligente Verwendung der GC-verwalteten Heap-Zuweisung festlegen, wann die Garbage Collection ausgeführt werden soll.





Die Strategien ab Punkt 2 eignen sich gut für Code, den der Programmierer selbst schreibt, sind jedoch nicht besonders hilfreich, wenn es um Bibliotheken von Drittanbietern geht. In diesen Fällen können Sie mithilfe der Mechanismen der D-Sprache und ihrer Laufzeit sicherstellen, dass an kritischen Punkten im Code keine Speicherzuweisung erfolgt. Es gibt auch Befehlszeilenoptionen, um sicherzustellen, dass GC Ihnen nicht im Weg steht.



Stellen wir uns vor, Sie schreiben ein D-Programm und haben aus dem einen oder anderen Grund beschlossen, die Speicherbereinigung vollständig zu eliminieren. Sie haben zwei offensichtliche Lösungen.



Pille gegen Gier



Die erste Lösung besteht darin, GC.disablebeim Starten des Programms aufzurufen . Das Zuweisen von Speicher über GC funktioniert weiterhin, die Speicherbereinigung wird jedoch gestoppt. Die gesamte Speicherbereinigung, einschließlich der Ereignisse in anderen Threads.



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


Ausgabe:



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



In zukünftigen Artikeln werden wir uns ansehen, wie Sie Speicher zuweisen können, ohne auf GC zurückzugreifen, und ihn parallel zum Speicher des GC verwenden, anstatt die im @nogcCode nicht verfügbaren Sprachfunktionen zu ersetzen , und vieles mehr.



Vielen Dank an Vladimir Panteleev, Guillaume Piolat und Steven Schveighoffer für ihr wertvolles Feedback zum Entwurf dieses Artikels.




All Articles