حافظهٔ مجازی از اصول اولیه
خلاصهٔ کاملتر
نویسنده میگه این مطلب حاصل چند ماه کار بوده و پوشش تقریباً کتاباندازهای از حافظهٔ مجازی میده؛ حدود ۲۵ هزار کلمه که یه نسخهٔ PDF و EPUB شصتصفحهای هم براش آماده شده. حرف پایهایش اینه که حافظهٔ مجازی برای ساختن و دیباگ کردن سیستمهای دادهمحور پرکارایی یه مهارت ضروریه، نه یه بحث آکادمیک.
قالب مطلب غیرمعموله و همین جذابش میکنه: بهجای فهرستی از تعریفها، داستان یه پروسهٔ تازهساختهشده به اسم Alloca روایت میشه که با کرنل حرف میزنه. Alloca سر راهش به مشکل میخوره و سؤال میپرسه و کرنل جواب میده. آخر هر بخش هم یه جعبهٔ «نکتهٔ کلیدی» هست که همون مفهوم رو رسمی و فشرده جمعبندی میکنه، پس اگه عجله داری فقط همونها رو بخون.
شروع ماجرا از یه سؤال سادهست: چرا اصلاً حافظهٔ مجازی؟ کرنل توضیح میده که آدرسی که پروسه دستشه آدرس واقعی نیست و اگه دهها پروسه همزمان دسترسی مستقیم به حافظهٔ فیزیکی داشتن، هیچ راهی برای هماهنگی و جلوگیری از خرابکردن دادهٔ همدیگه نبود. جداسازی، محافظت، و توهم حافظهٔ فراوان سه دستاورد اصلی این لایهن.
بخش بعدی چیدمان فضای آدرس رو باز میکنه: سگمنت کد که فقطخواندنی و اجراییه، سگمنت data برای متغیرهای سراسری مقداردهیشده، سگمنت bss برای متغیرهای صفر که هیچ بایتی تو فایل باینری اشغال نمیکنن، هیپ که با brk به بالا رشد میکنه، ناحیهٔ نگاشت حافظه برای کتابخونههای اشتراکی و mmap، و استک که از بالا به پایین میاد و روی x86-64 سقف پیشفرضش ۸ مگابایته.
یه نکتهٔ ظریف اینجاست: فضای آدرس مجازی یه پروسه میتونه ۱۲۸ ترابایت باشه در حالی که کل رم ماشین ۱۶ یا ۳۲ گیگابایته. پس بیشتر این فضا اصلاً نگاشت نشده و کرنل فقط چیزی رو که واقعاً لازم میشه و اون هم بهصورت تنبل نگاشت میکنه. دسترسی به یه آدرس تصادفی از اون ناحیه هم همون خطای segmentation آشناست.
دلیل این چیدمان دقیق دو چیزه: کارایی و امنیت. از طرف کارایی، پردازنده موقع خوندن یه مقدار، یه بلوک ۶۴ بایتی دور اونو (همون cache line) میاره و چون دسترسیها معمولاً محلی و ترتیبیان، این شرط اغلب برندهست. از طرف امنیت، هر سگمنت بیتهای دسترسی خودشو داره: کد فقطخواندنی و اجرایی، هیپ و استک خواندنی-نوشتنی ولی غیراجرایی — همون چیزی که بهش W^X میگن.
بقیهٔ مسیر مقاله سنگینتر میشه: ترجمهٔ آدرس با جدولهای صفحهٔ چهارسطحی و اینکه چرا سلسلهمراتب جلوی هدررفت حافظه رو میگیره، نقش MMU و TLB و اهمیت نرخ اصابت TLB، صفحهبندی بر اساس تقاضا و خطای صفحه، تفاوت حافظهٔ ناشناس و فایلپشتیبان و نحوهٔ بازپسگیریشون، کپی هنگام نوشتن و سرعت fork، ورودی-خروجی با mmap و حذف یه کپی اضافه، و در آخر اثر اندازهٔ صفحه و صفحههای بزرگ و چیدمان NUMA روی کارایی.
نویسنده تأکید میکنه لازم نیست یهنفس بخونیش و بخشها روی هم ساخته شدن، پس ترتیبی خوندنش بهتره؛ ولی اگه درس سیستمعامل گذروندی میتونی از بخشهای ابتدایی بپری. جزئیات پیادهسازی هم بر پایهٔ کرنل لینوکس و معماری x86-64 توضیح داده شدن.
نکات کلیدی:
- قالب گفتوگویی بین یه پروسه و کرنل، مفاهیم رو پلهپله میسازه
- هر بخش یه جعبهٔ جمعبندی داره که برای مرور سریع کافیه
- فضای آدرس به سگمنتهای کد، data، bss، هیپ، نگاشت حافظه و استک تقسیم میشه
- بیشتر فضای آدرس نگاشتنشدهست و نگاشت به شکل تنبل و بر اساس تقاضا انجام میشه
- پوشش پیشرفته: جدول صفحه، TLB، کپی هنگام نوشتن، mmap، صفحههای بزرگ و NUMA




