۱۳ آبان ۱۴۰۵ napcakes.nekoweb.org ۳ دقیقه مطالعه

باستان‌شناسی یونیکس: نگاهی به تاریخچه و تکامل مدیریت حافظه و malloc

باستان‌شناسی یونیکس: نگاهی به تاریخچه و تکامل مدیریت حافظه و malloc — The lost malloc()

خلاصه

این مقاله با بررسی کدهای اولیه نسخه‌های قدیمی سیستم‌عامل یونیکس، روند تکامل مدیریت حافظه در زبان C را از دهه‌ی ۷۰ میلادی بررسی می‌کند. برای توسعه‌دهندگان جذاب است که ببینند چگونه ایده‌های امروزی مانند Bump Allocator و ماکروهای تخصیص حافظه دهه‌ها پیش آزمایش شده‌اند.

مقدمه ای بر باستان‌شناسی سیستم‌عامل

با پیدا شدن نوار مغناطیسی گم‌شده‌ی نسخه‌ی چهارم یونیکس (UNIX v4) که در سال ۱۹۷۳ میلادی توسط آزمایشگاه‌های بل منتشر شده بود، فرصتی بی‌نظیر برای بررسی کدهای اولیه‌ی سیستم‌عامل فراهم شد. این نسخه از یونیکس که بخش عمده‌ی هسته‌ی آن به زبان C نوشته شده بود، نشان می‌دهد بسیاری از مفاهیمی که امروزه در دنیای POSIX بدیهی می‌دانیم، دهه‌ها پیش وجود داشته‌اند. یکی از جذاب‌ترین بخش‌ها در این میان، نحوه‌ی مدیریت حافظه و تخصیص آن در زبان C است.

تخصیص خطی حافظه (Linear Allocation)

با بررسی کدهای بخش‌های اولیه، با تابعی ساده برای تخصیص حافظه روبه‌رو می‌شویم که عملاً یک Bump Allocator ابتدایی است:

alloc(an) {
    register int n;
    register char *p;
    n = an;
    n++;
    n =& ~01;
    if (lasta+n >= lastr) {
        if (sbrk(2000) == -1) {
            write(2, "Out of space\n", 14);
            exit(1);
        }
        lastr =+ 2000;
    }
    p = lasta;
    lasta =+ n;
    return(p);
}

این تابع سایز را تراز می‌کند، چک می‌کند که آیا فضای کافی وجود دارد یا خیر، و در صورت نیاز با استفاده از سیستم‌کال sbrk حافظه را افزایش می‌دهد. در صورت بروز خطا نیز برنامه‌ی متوقف می‌شود. جالب اینجاست که توسعه‌دهندگان نیازی به آزادسازی حافظه (free) نداشتند، زیرا همه‌چیز تا پایان عمر برنامه زنده می‌ماند.

توابع malloc و mfree در کدهای اولیه

در دایرکتوری Dennis (دنیس ریچی)، فایلی به نام malloc.c وجود دارد که شامل توابع malloc و mfree است. نکته‌ی جالب اینجاست که این توابع یک آرگومان اضافی به نام mp (مخفف map) دریافت می‌کردند:

p = malloc(coremap, sizeof foo);
...
mfree(coremap, sizeof foo, p);

این توابع روی مناطق صریح حافظه (مانند coremap برای حافظه‌ی اصلی و swapmap برای فضای سواپ دیسک) کار می‌کردند. این طراحی به طراحان اجازه می‌داد حافظه را پارتیشن‌بندی کنند و حتی منابع را راحت‌تر مدیریت نمایند.

تکامل به سوی ماکروها و اپراتور new

با گذر به نسخه‌های بعدی (مانند V7 و V8)، تکامل زبان C و نحوه‌ی نوشتن برنامه‌ها بیشتر به چشم می‌خورد. در نسخه‌های بعدی، الگوهایی برای محاسبه‌ی اندازه‌ها و استفاده از ماکروها دیده می‌شود که شباهت زیادی به عملگر new در C++ دارند. بیورن استاروساتروپ (Bjarne Stroustrup) بعدها اشاره کرد که ایده‌ی عملگر new و delete در C++ برای جلوگیری از خطاهای انسانی، فرار از وابستگی به زباله‌روب (Garbage Collector) و ترکیب تخصیص حافظه با فراخوانی سازنده‌ها از زبان Simula الهام گرفته شده بود، هرچند ابزارهای اولیه‌ی مشابهی نیز در فضای ابزارهای یونیکس دیده‌می‌شدند.

دیدگاه برنامه‌نویسان در هکرنیوز

بحث‌های پیرامون این موضوع در Hacker News نشان می‌دهد که برنامه‌نویسان امروزی تا چه حد از دیدن این مفاهیم پایه‌ای در کدهای پنجاه سال پیش شگفت‌زده می‌شوند. دیدن اینکه تکنیک‌های مدرنی مانند Bump Allocator دهه‌ها پیش پیاده‌سازی و استفاده شده‌اند، یادآور ریشه‌های عمیق و مهندسی دقیق سیستم‌های کامپیوتری است.

این مطلب به‌صورت کاملاً خودکار و با هوش مصنوعی از مقالهٔ اصلی و بحث هکرنیوز تهیه شده و ممکن است خطا داشته باشد. حقوق مطلب اصلی متعلق به نویسندهٔ آن است. قوانین و گزارش مشکل

این خبر را با دیگران به اشتراک بگذارید

خبرهای فناوری در قالب پست و ویدیوی کوتاه، در اینستاگرام هکرنیوز بلاگ. به‌زودی
هر خبر به محض انتشار، به‌همراه پادکست روزانه در کانال تلگرام هکرنیوز بلاگ.