- 不要害怕收割者
- 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)对本文草案的宝贵反馈。