- 不要害怕收割者
- Life in the Fast Lane
- Go Your Own Way. .
- Go Your Own Way. .
在有关GC的系列文章的第一篇中,我介绍了D垃圾收集器和使用它的语言功能。我试图传达的两个关键点:
GC仅在您请求内存分配时运行。与普遍的误解相反,D语言GC无法在游戏循环中间简单地暂停和暂停Minecraft克隆。它仅在您请求通过它的内存时才运行,并且仅在需要时运行。
简单的C和C ++样式的内存分配策略可以减少GC的负担。不要在循环内分配内存-相反,请尽可能多地预分配资源或使用堆栈。最小化通过GC分配的内存总数。这些策略因#1而起作用。开发人员可以通过智能地使用GC管理的堆分配来指示何时运行垃圾回收。
从第2点开始的策略对于程序员自己编写的代码而言是不错的选择,但是对于第三方库而言,它们并不是特别有用。在这些情况下,使用D语言及其运行时的机制,可以确保在代码的关键点上没有发生内存分配。还有一些命令行选项可以帮助确保GC不会妨碍您。
假设您正在编写D程序,并且出于一个或另一个原因决定完全消除垃圾回收。您有两个明显的解决方案。
贪婪药
第一个解决方案是GC.disable在程序启动时调用。通过GC分配内存仍将起作用,但是垃圾收集将停止。所有垃圾回收,包括可能在其他线程上发生的一切。
void main() {
import core.memory;
import std.stdio;
GC.disable;
writeln("Goodbye, GC!");
}
输出:
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. , , .
在以后的文章中,我们将探讨如何在不求助于GC的情况下分配内存,并将其与GC中的内存并行使用,而不是替换@nogc代码中不可用的语言功能,等等。
感谢弗拉基米尔·潘捷列夫(Vladimir Panteleev),纪尧姆·皮奥拉特(Guillaume Piolat)和史蒂芬·施维霍夫(Steven Schveighoffer)对本文草案的宝贵反馈。