לדלג לתוכן

פתרון מקצים וערמות משתמש

הסדרים השונים יכולים להשפיע על reuse ועל ארגון בלוקים פנויים, אבל אין תוצאה אוניברסלית שכל heap חייב להציג. צריך לשמור גרסת מערכת, מצב debugger ו־flags כדי שההשוואה תהיה משמעותית.

בעלות בטוחה יכולה להחזיק את ה־heap באובייקט חיצוני ואת הבלוקים באובייקטים פנימיים שנבנים אחריו. העברת block לבעלים שחי יותר מה־heap אינה חוקית, גם אם יש לו destructor שנראה נכון.

הקטע הבא מדגים בנייה והשמדה של אובייקט ב־heap שכבר נוצר. הוא מצטרף לתוכנית עם <memory>, ומניח שה־heap נשאר חי לאורך כל הפעולות.

struct Counted {
    unsigned* destroyed;
    ~Counted() { ++*destroyed; }
};
unsigned destroyed = 0;
void* storage = HeapAlloc(heap, 0, sizeof(Counted));
if (!storage) {
    HeapDestroy(heap);
    return 3;
}
Counted* item = std::construct_at(static_cast<Counted*>(storage), &destroyed);
std::destroy_at(item);
if (!HeapFree(heap, 0, storage)) {
    HeapDestroy(heap);
    return 4;
}
std::printf("destroyed=%u\n", destroyed);

הקוד משתמש בטיפוס שיישורו מתאים להקצאה הרגילה. אם מסירים את destroy_at ומשמידים את ה־heap, אחסון האובייקט נעלם אך המונה אינו מתעד destructor. זהו ניסוי בעל משמעות רק בטיפוס שאינו מחזיק משאב חיצוני חשוב; אין צורך לייצר דליפת handle אמיתית כדי להבין את ההבדל.

עומס שמחזיק בלוקים ארוכים ומחליף ביניהם הרבה בלוקים קצרים יכול לבדוק האם האחסון הפנוי נעשה מפוצל. המדידה צריכה להבחין בין bytes שהתבקשו, bytes שהמקצה מחזיק ו־commit של התהליך.

ב־arena, כשל באמצע הבקשה אינו פוטר מהשמדת אובייקטים שכבר נבנו אם יש להם destructors משמעותיים. רק לאחר ההשמדה אפשר לאפס את ה־arena. שחרור גוש זיכרון אחד מהיר, אבל סדר הניקוי של משאבים אחרים עדיין קיים.

ההשוואה ההנדסית כוללת גם peak memory וכשל, ולא רק זמן במסלול הצלחה. מקצה שמחזיק הרבה יותר זיכרון יכול להיות בחירה נכונה, כל עוד המחיר מפורש ומתאים לתקציב.