- Don’t Fear the Reaper
- Life in the Fast Lane
- Go Your Own Way. .
- Go Your Own Way. .
نواصل سلسلة مقالاتنا حول أداة تجميع البيانات المهملة بلغة D. هذا هو الجزء الثاني من المقالة المخصص لتخصيص الذاكرة خارج GC. تحدث الجزء الأول عن تخصيص الذاكرة على المكدس. الآن سننظر في تخصيص الذاكرة من الكومة.
في حين أن هذا هو المنشور الرابع فقط في هذه السلسلة ، فهذه هي الثالثة التي أتحدث فيها عن طرق لتجنب استخدام GC. لا نخطئ: أنا لا أحاول إخافة المبرمجين من جامع القمامة D. بل على العكس تمامًا. يعد فهم متى وكيف يتم الاستغناء عن GC أمرًا ضروريًا لاستخدامه بفعالية.
مرة أخرى ، سأقول أنه من أجل جمع القمامة بكفاءة ، تحتاج إلى تقليل الحمل على GC. كما هو مذكور في المقالات الأولى واللاحقة من السلسلة ، هذا لا يعني أنه يجب التخلي عنها تمامًا. هذا يعني أنك بحاجة إلى أن تكون حكيماً بشأن مقدار وتكرار تخصيص الذاكرة من خلال GC. كلما قلت عمليات تخصيص الذاكرة ، قل عدد الأماكن المتبقية التي يمكن أن تبدأ فيها عملية جمع البيانات المهملة. كلما قلت الذاكرة الموجودة في كومة أداة تجميع البيانات المهملة ، قل حجم الذاكرة التي تحتاجها للمسح.
من المستحيل التحديد الدقيق والشامل للتطبيقات التي سيكون تأثير GC فيها ملحوظًا وأيها لن يكون كذلك - يعتمد الأمر كثيرًا على البرنامج المحدد. ولكن يمكننا أن نقول بأمان أنه في معظم التطبيقات لا توجد حاجة لتعطيل GC مؤقتًا أو كليًا ، ولكن عندما لا تزال هناك حاجة إليه ، من المهم معرفة كيفية الاستغناء عنه. الحل الواضح هو تخصيص ذاكرة على المكدس ، لكن D يسمح أيضًا بتخصيص الذاكرة على الكومة العادية ، متجاوزًا GC.
كلي الوجود شي
للأفضل أو للأسوأ ، C في كل مكان حولنا. اليوم ، يشير أي برنامج ، في أي لغة يمكن كتابتها ، في بعض المستويات على الأرجح إلى واجهة برمجة تطبيقات C. على الرغم من أن مواصفات C لا تحدد معيار ABI ، إلا أن المراوغات الخاصة بالنظام الأساسي معروفة على نطاق واسع بأنها تتفاعل معها معظم اللغات بمهارة. اللغة د ليست استثناء. في الواقع ، تتمتع جميع برامج D بإمكانية الوصول إلى مكتبة C القياسية افتراضيًا.
الحزمة core.stdc عبارة عن مجموعة من وحدات 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
, , .