- Don’t Fear the Reaper
- Life in the Fast Lane
- Go Your Own Way. .
- Go Your Own Way. .
Dガベージコレクターに関する一連の記事を続けます。これは、GC外でのメモリ割り当てに関する記事の第2部です。最初の部分では、スタックにメモリを割り当てる方法について説明しました。次に、ヒープからのメモリ割り当てについて見ていきます。
これはこのシリーズの4番目の投稿にすぎませんが、GCの使用を回避する方法について説明するのは3番目です。間違いありません。私はプログラマーをDガベージコレクターから追い払おうとはしていません。まったく逆です。GCを効果的に使用するには、GCを使用しない時期と方法を理解することが不可欠です。
繰り返しになりますが、効率的なガベージコレクションを行うには、GCの負荷を軽減する必要があります。シリーズの最初と後続の記事で述べたように、これはそれが完全に放棄されるべきであることを意味するものではありません。これは、GCを介してメモリを割り当てる量と頻度について慎重に検討する必要があることを意味します。メモリ割り当てが少ないほど、ガベージコレクションを開始できる場所が少なくなります。ガベージコレクターのヒープにあるメモリが少ないほど、スキャンする必要のあるメモリも少なくなります。
どのアプリケーションでGCの影響が顕著で、どのアプリケーションで顕著であるかを正確かつ包括的に判断することは不可能です。特定のプログラムに大きく依存します。しかし、ほとんどのアプリケーションでは、GCを一時的または完全に無効にする必要はないと言っても過言ではありませんが、それでも必要な場合は、GCなしで行う方法を知ることが重要です。明らかな解決策はスタックにメモリを割り当てることですが、Dを使用すると、GCをバイパスして、通常のヒープにメモリを割り当てることもできます。
遍在するXi
, C . , , - API C. , C ABI, - , . D — . , D C.
core.stdc — D, C. D, C. , .
import core.stdc.stdio : puts;
void main()
{
puts("Hello C standard library.");
}
, D, , C extern(C)
, , D as a Better C [], -betterC
. , . D C , extern(C)
. puts
core.stdc.stdio
— , , .
malloc
D C, , malloc
, calloc
, realloc
free
. , core.stdc.stdlib
. D GC .
import core.stdc.stdlib;
void main()
{
enum totalInts = 10;
// 10 int.
int* intPtr = cast(int*)malloc(int.sizeof * totalInts);
// assert(0) ( assert(false)) ,
// assert ,
// malloc.
if(!intPtr) assert(0, "Out of memory!");
// .
// , ,
// .
scope(exit) free(intPtr);
// ,
// +.
int[] intArray = intPtr[0 .. totalInts];
}
GC, D . T
, GC, T.init
— int
0
. D, . malloc
calloc
, . , float.init
— float.nan
, 0.0f
. .
, , malloc
free
. :
import core.stdc.stdlib;
// , .
void[] allocate(size_t size)
{
// malloc(0) ( null - ), , .
assert(size != 0);
void* ptr = malloc(size);
if(!ptr) assert(0, "Out of memory!");
// ,
// .
return ptr[0 .. size];
}
T[] allocArray(T)(size_t count)
{
// , !
return cast(T[])allocate(T.sizeof * count);
}
// deallocate
void deallocate(void* ptr)
{
// free handles null pointers fine.
free(ptr);
}
void deallocate(void[] mem)
{
deallocate(mem.ptr);
}
void main() {
import std.stdio : writeln;
int[] ints = allocArray!int(10);
scope(exit) deallocate(ints);
foreach(i; 0 .. 10) {
ints[i] = i;
}
foreach(i; ints[]) {
writeln(i);
}
}
allocate
void[]
void*
, length
. , , allocate
, allocArray
, , allocate
, . , C , — , , . calloc
realloc
, , C.
, (, allocArray
) -betterC
, . D.
, -
, GC, , . , ~=
~
, , GC. ( ). . , , GC.
import core.stdc.stdlib : malloc;
import std.stdio : writeln;
void main()
{
int[] ints = (cast(int*)malloc(int.sizeof * 10))[0 .. 10];
writeln("Capacity: ", ints.capacity);
//
int* ptr = ints.ptr;
ints ~= 22;
writeln(ptr == ints.ptr);
}
:
Capacity: 0
false
0
, . , GC, , . , , . GC , , . , ints
GC, , (. D slices ).
, , , - , malloc
.
:
void leaker(ref int[] arr)
{
...
arr ~= 10;
...
}
void cleaner(int[] arr)
{
...
arr ~= 10;
...
}
, — , , . , (, length
ptr
) . — .
leaker
, C, GC. : , free
ptr
( , GC, C), . cleaner
. , , . GC, ptr
.
, . cleaner
, . , , , @nogc
. , , malloc
, free
, , .
Array
std.container.array
: GC, , .
API
C — . malloc
, . , . API: , Win32 HeapAlloc ( core.sys.windows.windows
). , D , GC.
, . . . .
, int
.
struct Point { int x, y; }
Point* onePoint = cast(Point*)malloc(Point.sizeof);
Point* tenPoints = cast(Point*)malloc(Point.sizeof * 10);
, . malloc
D. , Phobos , .
std.conv.emplace
, void[]
, , . , emplace
malloc
, allocate
:
struct Vertex4f
{
float x, y, z, w;
this(float x, float y, float z, float w = 1.0f)
{
this.x = x;
this.y = y;
this.z = z;
this.w = w;
}
}
void main()
{
import core.stdc.stdlib : malloc;
import std.conv : emplace;
import std.stdio : writeln;
Vertex4f* temp1 = cast(Vertex4f*)malloc(Vertex4f.sizeof);
Vertex4f* vert1 = emplace(temp1, 4.0f, 3.0f, 2.0f);
writeln(*vert1);
void[] temp2 = allocate(Vertex4f.sizeof);
Vertex4f* vert2 = emplace!Vertex4f(temp2, 10.0f, 9.0f, 8.0f);
writeln(*vert2);
}
emplace
. , D . , Vertex4f
:
struct Vertex4f
{
// x, y z float.nan
float x, y, z;
// w 1.0f
float w = 1.0f;
}
void main()
{
import core.stdc.stdlib : malloc;
import std.conv : emplace;
import std.stdio : writeln;
Vertex4f vert1, vert2 = Vertex4f(4.0f, 3.0f, 2.0f);
writeln(vert1);
writeln(vert2);
auto vert3 = emplace!Vertex4f(allocate(Vertex4f.sizeof));
auto vert4 = emplace!Vertex4f(allocate(Vertex4f.sizeof), 4.0f, 3.0f, 2.0f);
writeln(*vert3);
writeln(*vert4);
}
:
Vertex4f(nan, nan, nan, 1)
Vertex4f(4, 3, 2, 1)
Vertex4f(nan, nan, nan, 1)
Vertex4f(4, 3, 2, 1)
, emplace
, — . int
float
. , , . , emplace
, .
std.experimental.allocator
. , - , std.experimental.allocator
D. API, , , (Design by Introspection), , , . Mallocator
GCAllocator
, , - . — emsi-containers.
GC
GC , D, GC, , GC. , GC. , malloc
, new
.
GC GC.addRange
.
import core.memory;
enum size = int.sizeof * 10;
void* p1 = malloc(size);
GC.addRange(p1, size);
void[] p2 = allocate!int(10);
GC.addRange(p2.ptr, p2.length);
, GC.removeRange
, . . free
, . , .
GC , , , . . , , . GC , . addRange
. , GC, addRange
.
addRange
. C , .
struct Item { SomeClass foo; }
auto items = (cast(Item*)malloc(Item.sizeof * 10))[0 .. 10];
GC.addRange(items.ptr, items.length);
GC 10 . length
. , — void[]
( , byte
ubyte
). :
GC.addRange(items.ptr, items.length * Item.sizeof);
API , , void[]
.
void addRange(void[] mem)
{
import core.memory;
GC.addRange(mem.ptr, mem.length);
}
addRange(items)
. void[]
, mem.length
, items.length * Item.sizeof
.
GC
この記事では、GCを使用せずにヒープを使用する方法の非常に基本的な方法について説明しました。クラスに加えて、私たちのストーリーには別のギャップが残っています。それは、破壊者をどうするかです。このトピックは、次の記事のために保存しておきます。このシリーズの次のGCで計画されているものは次のとおりです。連絡を取り合いましょう!
Walter Bright、Guillaume Piolat、Adam D. Ruppe、Steven Schveighofferの、この記事の作成に貴重な支援をしてくれたことに感謝します。
, . , , . APIcore.memory.GC
inFinalizer
, , .