- Fürchte den Schnitter nicht
- Life in the Fast Lane
- Go Your Own Way. .
- Go Your Own Way. .
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:
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.
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.disable
beim 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.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 @nogc
Code 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.