- Ne craignez pas le faucheur
- Life in the Fast Lane
- Go Your Own Way. .
- Go Your Own Way. .
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:
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.
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.disable
lorsque 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.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 @nogc
fonctionnalité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.