0Pricing
C Academy · درس

المحاذاة والتقسيم

اجعل الكتل قابلة للاستخدام ومنظمة

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

لماذا تهم المحاذاة

لكل نوع متطلب محاذاة: يجب أن يكون عنوانه من مضاعفات قوة معينة للعدد اثنين. ويحتاج double عادةً إلى محاذاة بمقدار 8 بايتات.

ولأن malloc لا يعرف ما ستخزنونه، فعليه إرجاع مؤشرات محاذاة لأشد الأنواع متطلبات، وعادةً ما تكون المحاذاة 16 بايتًا في الأنظمة ذات 64 بت.

#include <stdalign.h>
/* the strictest fundamental alignment */
size_t strict = alignof(max_align_t);   /* often 16 */

حيلة align_up

تقريب حجم إلى أعلى مضاعف لمحاذاة تمثل قوةً للعدد اثنين هو حيلة بتّية شائعة: أضيفوا a - 1، ثم أزيلوا البتات الدنيا باستخدام قناع.

ولا تعمل هذه الطريقة إلا عندما تكون a قوةً للعدد اثنين، وهو حال جميع قيم المحاذاة الفعلية.

static size_t align_up(size_t n, size_t a) {
    return (n + a - 1) & ~(a - 1);
}
/* align_up(13, 8) == 16, align_up(16, 8) == 16 */

إثبات عمل الحسابات

لنتحقق من align_up باستخدام برنامج قابل للتشغيل. فهو يقرّب عدة أحجام إلى أعلى حدود مقدارها 8 و16 بايتًا، ثم يطبع النتائج.

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

static size_t align_up(size_t n, size_t a) {
    return (n + a - 1) & ~(a - 1);
}

int main(void) {
    printf("%zu\n", align_up(13, 8));   /* 16 */
    printf("%zu\n", align_up(16, 8));   /* 16 */
    printf("%zu\n", align_up(1, 16));   /* 16 */
    printf("%zu\n", align_up(33, 16));  /* 48 */
    return 0;
}

محاذاة الأحجام المطلوبة

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

وتُعد بايتات الحشو تجزئةً داخلية، وهي ثمن المحاذاة الشاملة.

#define ALIGN 16
void *my_alloc(size_t size) {
    size = align_up(size, ALIGN);
    /* now find a block of this aligned size */
    /* ... */
    return NULL;
}

مشكلة إعادة استخدام الكتلة بأكملها

في الدرس السابق، أعدنا كتلة حرة كاملة حتى مع الطلبات الصغيرة. فعندما تُمنح كتلة حرة بحجم 4000 بايت لطلب حجمه 16 بايتًا، تُهدر المساحة المتبقية.

يقطّع التقسيم الكتلة إلى الجزء الذي نستخدمه وبقية تظل حرة.

تقسيم كتلة

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

لا نقسم إلا عندما تكون المساحة المتبقية كبيرة بما يكفي لاحتواء ترويسة وبعض الحمولة، وإلا أصبح الجزء المتناثر عديم الفائدة.

void split(block_t *b, size_t size) {
    size_t rem = b->size - size;
    if (rem < sizeof(block_t) + ALIGN) return; /* too small */
    block_t *nb = (block_t *)((char *)(b + 1) + size);
    nb->size = rem - sizeof(block_t);
    nb->free = 1;
    nb->next = b->next;
    b->size = size;
    b->next = nb;
}

التخصيص والمحاذاة والتقسيم

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

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

void *my_alloc(size_t size) {
    size = align_up(size, ALIGN);
    block_t *b = first_fit(size);
    if (!b) return NULL;
    split(b, size);
    b->free = 0;
    return (void *)(b + 1);
}

الحفاظ على محاذاة المجمّع نفسه

لضمان الصحة، ينبغي أن يحترم عنوان بدء المجمّع وحجم الترويسة المحاذاة أيضًا، بحيث تقع كل حمولة على حدّ محاذاة.

يضمن استخدام alignas على المخزن المؤقت الساكن بدء المخطط بأكمله بمحاذاة صحيحة.

#include <stdalign.h>
alignas(16) static unsigned char pool[4096];
/* pool now begins on a 16-byte boundary */

تخصيص بمحاذاة قابل للتشغيل

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

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

static size_t align_up(size_t n, size_t a){ return (n+a-1)&~(a-1); }
alignas(16) static unsigned char pool[1024];
static size_t off = 0;

void *alloc16(size_t s){ off=align_up(off,16); if(off+s>sizeof(pool)) return NULL; void*p=&pool[off]; off+=s; return p; }

int main(void){
    void *a = alloc16(1);
    void *b = alloc16(20);
    printf("a %% 16 = %lu\n", (unsigned long)((size_t)a % 16));
    printf("b %% 16 = %lu\n", (unsigned long)((size_t)b % 16));
    return 0;
}

التقسيم في مقابل الدمج

التقسيم والدمج عمليتان متعاكستان توازنان بين بعضهما. فالتخصيص يقسم الكتل الكبيرة إلى أجزاء أصغر، بينما يدمج التحرير الكتل الصغيرة من جديد.

وتتيحان معًا للمجمّع نفسه خدمة مزيج متغير من أحجام الطلبات دون هدر المساحة أو تجزئتها بشكل دائم.

من مخصّص تجريبي إلى مخصّص حقيقي

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

لكن الأفكار الأساسية التي بنيتموها هنا تشغّل كل تطبيقات malloc.

تحقّق سريع

فكّروا في سبب تقسيم الكتل أثناء التخصيص.

مراجعة

تقرّب المحاذاة الأحجام إلى أعلى باستخدام الحيلة البتّية (n + a - 1) & ~(a - 1)، بحيث تناسب كل حمولة أي نوع. ويقتطع التقسيم الكتل الحرة الأكبر من المطلوب إلى جزء مستخدم وبقية حرة، بينما يعكس الدمج ذلك عند التحرير.

وتشكّل هذه الأعمدة الأربعة معًا مخصّص ذاكرة كاملًا وصحيحًا.

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

هل درس «المحاذاة والتقسيم» مجاني؟

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

ماذا ستتعلم في «المحاذاة والتقسيم»؟

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

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

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

كم من الوقت يستغرق درس «المحاذاة والتقسيم»؟

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

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

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

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

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