- Don’t Fear the Reaper
- Life in the Fast Lane
- Go Your Own Way. .
- Go Your Own Way. .
Nous continuons notre série d'articles sur le garbage collector en langage D. Ceci est la deuxième partie de l'article consacrée à l'allocation de mémoire en dehors du GC. La première partie parlait d'allocation de mémoire sur la pile. Nous allons maintenant examiner l'allocation de mémoire à partir du tas.
Bien que ce ne soit que le quatrième article de cette série, c'est le troisième dans lequel je parle des moyens d' éviter d' utiliser GC. Ne vous y trompez pas: je n’essaie pas d’effrayer les programmeurs du ramasse-miettes D. Bien au contraire. Comprendre quand et comment se passer de GC est essentiel pour l'utiliser efficacement.
Encore une fois, je dirai que pour un garbage collection efficace, vous devez réduire la charge sur le GC. Comme mentionné dans le premier article et les articles suivants de la série, cela ne signifie pas qu'elle doit être complètement abandonnée. Cela signifie que vous devez être judicieux sur la quantité et la fréquence d'allocation de mémoire via le GC. Moins il y a d'allocations de mémoire, moins il reste d'endroits où le garbage collection peut démarrer. Moins il y a de mémoire sur le tas du garbage collector, moins il a besoin de mémoire pour analyser.
Il est impossible de déterminer de manière précise et exhaustive dans quelles applications l'impact de la GC sera perceptible et dans lesquelles non - cela dépend beaucoup du programme spécifique. Mais nous pouvons affirmer avec certitude que dans la plupart des applications, il n'est pas nécessaire de désactiver temporairement ou complètement GC, mais quand c'est encore nécessaire, il est important de savoir comment s'en passer. La solution évidente est d'allouer de la mémoire sur la pile, mais D permet également d'allouer de la mémoire sur le tas normal, en contournant le GC.
Xi omniprésent
, 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
Cet article a couvert les bases de l'utilisation du tas sans recourir à GC. En plus des classes, il reste une autre lacune béante dans notre histoire: que faire des destructeurs. Je garderai ce sujet pour le prochain article, où il sera très approprié. Voici ce qui est prévu pour le prochain GC de cette série. Reste en contact!
Merci à Walter Bright, Guillaume Piolat, Adam D. Ruppe et Steven Schveighoffer pour leur aide précieuse dans la préparation de cet article.
, . , , . APIcore.memory.GC
inFinalizer
, , .