- Donβt Fear the Reaper
- Life in the Fast Lane
- Go Your Own Way. .
- Go Your Own Way. .
Kami melanjutkan seri artikel kami tentang pengumpul sampah D. Ini adalah bagian kedua dari artikel tentang alokasi memori di luar GC. Bagian pertama berbicara tentang mengalokasikan memori pada stack. Sekarang kita akan melihat alokasi memori dari heap.
Meskipun ini hanya posting keempat dalam seri ini, ini adalah posting ketiga di mana saya berbicara tentang cara menghindari penggunaan GC. Jangan salah: Saya tidak mencoba untuk menakut-nakuti programmer dari pengumpul sampah D. Justru sebaliknya. Memahami kapan dan bagaimana tidak menggunakan GC sangat penting untuk menggunakannya secara efektif.
Sekali lagi, saya akan mengatakan bahwa untuk pengumpulan sampah yang efisien, Anda perlu mengurangi beban pada GC. Seperti yang disebutkan dalam artikel pertama dan selanjutnya dari seri ini, ini tidak berarti bahwa artikel tersebut harus sepenuhnya ditinggalkan. Ini berarti Anda harus berhati-hati tentang seberapa banyak dan seberapa sering mengalokasikan memori melalui GC. Semakin sedikit alokasi memori, semakin sedikit tempat yang tersisa untuk memulai pengumpulan sampah. Semakin sedikit memori di heap pengumpul sampah, semakin sedikit memori yang perlu dipindai.
Tidak mungkin untuk secara akurat dan komprehensif menentukan di aplikasi mana dampak GC akan terlihat dan mana yang tidak - itu sangat tergantung pada program tertentu. Namun kami dapat dengan aman mengatakan bahwa di sebagian besar aplikasi tidak perlu menonaktifkan GC untuk sementara atau seluruhnya, tetapi jika masih diperlukan, penting untuk mengetahui cara melakukannya tanpa GC. Solusi yang jelas adalah mengalokasikan memori pada stack, tetapi D juga memungkinkan memori dialokasikan pada heap biasa, melewati GC.
Xi yang ada di mana-mana
, 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
Artikel ini telah membahas dasar-dasar tentang cara menggunakan heap tanpa menggunakan GC. Selain kelas, ada celah lain yang tersisa dalam cerita kita: apa yang harus dilakukan dengan destruktor. Saya akan menyimpan topik ini untuk artikel berikutnya, yang akan sangat sesuai. Inilah yang direncanakan untuk GC berikutnya dalam seri ini. Tetap berhubungan!
Terima kasih kepada Walter Bright, Guillaume Piolat, Adam D. Ruppe, dan Steven Schveighoffer atas bantuan mereka yang tak ternilai dalam mempersiapkan artikel ini.
, . , , . APIcore.memory.GC
inFinalizer
, , .