0Pricing
C Academy · درس

مخصّص Bump بسيط

وزّع الذاكرة خطيًا

مخصّص Bump بسيط درس مجاني في C Academy على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في C Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة C Academy 4 دروس في المجموع.

فكرة المخصص المتزايد

المخصص المتزايد (أو مخصص الساحة) هو أبسط تصميم. تحتفظ بمخزن مؤقت كبير وإزاحة واحدة. يعيد كل تخصيص الإزاحة الحالية، ثم «يدفع» الإزاحة إلى الأمام بمقدار الحجم المطلوب.

لا توجد بيانات تعريف لكل كتلة ولا عملية بحث. فالتخصيص هو في الأساس عملية جمع واحدة للمؤشر، مما يجعله سريعًا جدًا.

مخزن مؤقت ثابت داعم

لدينا مثال مستقل، ندعم المخصص بمصفوفة ثابتة بدلًا من كومة نظام التشغيل. يُترجم هذا المثال ويعمل في أي مكان، من دون sbrk أو mmap.

تمنحنا المصفوفة مجموعة ثابتة من البايتات لتقسيمها.

#define POOL_SIZE 1024
static unsigned char pool[POOL_SIZE];
static size_t offset = 0;

الدالة الأساسية bump

يتحقق التخصيص من بقاء مساحة كافية، ويسجل البداية، ويقدم الإزاحة، ثم يعيد مؤشر البداية. وإذا كان الطلب سيتجاوز سعة التجميعة، فإنه يعيد NULL.

فحص التجاوز هذا هو إجراء الأمان الوحيد الذي يوفره المخصص المتزايد.

void *bump_alloc(size_t size) {
    if (offset + size > POOL_SIZE)
        return NULL;            /* out of pool */
    void *p = &pool[offset];
    offset += size;
    return p;
}

مخصص متزايد كامل قابل للتشغيل

إليك برنامجًا كاملًا. يخصص عددين صحيحين وسلسلة قصيرة من التجميعة ويطبعهما، مما يثبت عمل المخصص.

لاحظ قلة الشيفرة المطلوبة مقارنةً بـ malloc حقيقي.

#include <stdio.h>
#include <stddef.h>
#include <string.h>

#define POOL_SIZE 1024
static unsigned char pool[POOL_SIZE];
static size_t offset = 0;

void *bump_alloc(size_t size) {
    if (offset + size > POOL_SIZE) return NULL;
    void *p = &pool[offset];
    offset += size;
    return p;
}

int main(void) {
    int *a = bump_alloc(sizeof(int));
    int *b = bump_alloc(sizeof(int));
    char *s = bump_alloc(6);
    *a = 10; *b = 32;
    strcpy(s, "hi");
    printf("%d %d %s\n", *a, *b, s);
    printf("used = %zu\n", offset);
    return 0;
}

لا يوجد تحرير فردي

لكن هناك مشكلة: لا يستطيع المخصص المتزايد تحرير تخصيص واحد. وبما أنه لا توجد بيانات تعريف، فلا يعرف أين تنتهي كتلة وأين تبدأ التالية لإعادة استخدامها.

لا يمكنك سوى إعادة ضبط الساحة بأكملها دفعة واحدة، وذلك بتعيين الإزاحة إلى الصفر.

void bump_reset(void) {
    offset = 0;   /* frees everything at once */
}

لماذا تفيد إعادة الضبط؟

يناسب هذا النموذج الكلي أو لا شيء العملَ القائم على مراحل تمامًا: خصص كائنات كثيرة أثناء طلب أو إطار، ثم أعد ضبط الساحة عند انتهاء المرحلة.

تستخدم محركات الألعاب والمترجمات الساحات بكثرة، لأن إعادة ضبطها هي O(1) وتتجنب تتبع آلاف عمليات التحرير الفردية.

/* Per-frame pattern */
for (int frame = 0; frame < 3; frame++) {
    void *tmp = bump_alloc(128);
    /* ... use tmp this frame ... */
    bump_reset();   /* reclaim instantly */
}

تتبّع المساحة المتبقية

من المفيد إتاحة معرفة مقدار المساحة المتبقية. وهذا يساوي ببساطة حجم المجمّع ناقص الإزاحة الحالية.

يمكن للجهات المستدعية استخدام ذلك لتحديد ما إذا كان ينبغي تفريغ المجمّع أو توسيعه قبل طلب مساحة إضافية.

size_t bump_remaining(void) {
    return POOL_SIZE - offset;
}

عرض توضيحي قابل للتشغيل لإعادة الضبط

يملأ هذا البرنامج جزءًا من المجمّع، ويطبع مقدار الاستخدام، ثم يعيد ضبطه، ويُظهر عودة الإزاحة إلى الصفر بحيث تصبح المساحة قابلة لإعادة الاستخدام.

#include <stdio.h>
#include <stddef.h>

#define POOL_SIZE 256
static unsigned char pool[POOL_SIZE];
static size_t offset = 0;

void *bump_alloc(size_t s){ if(offset+s>POOL_SIZE) return NULL; void *p=&pool[offset]; offset+=s; return p; }
void bump_reset(void){ offset = 0; }

int main(void) {
    bump_alloc(100);
    printf("after alloc: used=%zu\n", offset);
    bump_reset();
    printf("after reset: used=%zu\n", offset);
    return 0;
}

المحاذاة في مخصّص الزيادة التدريجية

قد تؤدي الزيادة التدريجية الخام بايتًا تلو الآخر إلى إرجاع مؤشرات غير محاذاة. ولضمان الأمان، قرّب الإزاحة إلى أعلى حدّ محاذاة قبل إرجاع المؤشر.

سنتناول الحسابات بالتفصيل لاحقًا، لكن المحاذاة تكون أهم ما يكون في مخصّص الزيادة التدريجية، لأنه لا توجد حشوة تلقائية بخلاف ذلك.

static size_t align_up(size_t n, size_t a) {
    return (n + a - 1) & ~(a - 1);   /* a must be power of 2 */
}

مخصّص زيادة تدريجية بمحاذاة

بدمج الأجزاء، نحاذي الإزاحة قبل كل عملية تخصيص. ويضمن ذلك أن يكون كل مؤشر مُرجع مناسبًا لأي نوع شائع.

وتتمثل الكلفة في بعض التجزئة الداخلية الناتجة عن بايتات الحشو.

#define ALIGN 16
void *bump_aligned(size_t size) {
    offset = align_up(offset, ALIGN);
    if (offset + size > POOL_SIZE) return NULL;
    void *p = &pool[offset];
    offset += size;
    return p;
}

نقاط القوة والحدود

تتميّز مخصّصات الزيادة التدريجية بسرعة لا تُضاهى وبساطة شديدة، مع انعدام الكلفة الإضافية لكل كائن. وهي مثالية عندما تشترك الكائنات في دورة حياة واحدة.

أما نقطة ضعفها فهي عدم إتاحة التحرير الدقيق لكل كائن. وعندما تختلف دورات الحياة، تحتاجون إلى تصميم قائمة الكتل الحرة الذي سنتناوله في الدرس التالي.

تحقّق سريع

فكّروا في كيفية استعادة مخصّص الزيادة التدريجية للذاكرة.

مراجعة

يمنح مخصّص الزيادة التدريجية الذاكرةَ عبر تقديم الإزاحة خلال مخزن مؤقت، مما يجعل التخصيص رخيصًا بقدر إضافة إلى مؤشر.

وهو يضحّي بإمكانية تحرير كل كائن على حدة لصالح السرعة والبساطة، ولا يستعيد الذاكرة إلا عبر إعادة ضبط كاملة. حاذوا الإزاحة للحفاظ على صلاحية المؤشرات المُرجعة لجميع الأنواع.

الأسئلة الشائعة

هل درس «مخصّص Bump بسيط» مجاني؟

نعم — نص درس «مخصّص Bump بسيط» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة C Academy، انتقل إلى CoddyKit PRO. تتضمن دورة C Academy 4 دروس في المجموع.

ماذا ستتعلم في «مخصّص Bump بسيط»؟

وزّع الذاكرة خطيًا تتمرن على C Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ C Academy؟

لا تُشترط خبرة سابقة. C Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.

كم من الوقت يستغرق درس «مخصّص Bump بسيط»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس C Academy هذا؟

نعم. كل درس في C Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. كيف تعمل malloc
  2. مخصّص Bump بسيط
  3. قوائم الذاكرة الحرة وإعادة الاستخدام
  4. المحاذاة والتقسيم
← العودة إلى C Academy