محمد امین سلطانی
محمد امین سلطانی
خواندن ۳ دقیقه·۴ سال پیش

مدیریت حافظه در طراحی کامپایلر (قسمت 2)

در ادامه مطالب قبلی به این می‌پردازیم که چالش های موجود هنگام تخصیص حافظه به روش پشته چیست؟

https://vrgl.ir/n06nV

دو چالش مهم در این روش وجود دارد که با مثال به تشریح آن ها می‌پردازیم:

فرض کنید شما قرار است به عنوان برنامه نویس برنامه ای بنویسید تا از کاربر نام و نام خانوادگی را دریافت کند. معمولا پیاده سازی این برنامه در زبان C به این صورت است که یک آرایه از نوع کاراکتر ایجاد می‌کنیم و لازم است تا مقداری برای آن در نظر بگیریم. چون ما از قبل اطلاعی درباره تعداد کاراکتر های نام و نام خانوادگی کاربر نداریم پس باید یک حد مناسبی از آن را در نظر بگیریم. مثلا طول آرایه را به اندازه 30 خانه مقدار دهی می‌کنیم. حال اگر تعداد کاراکتر های واردی نام و نام خانوادگی کاربر کمتر از 30 عدد باشد (مثلا 20 کاراکتر) ما 10 کاراکتر از مقدار حافظه ای که دریافت کرده ایم را هدر داده‌ایم (به این چالش اصطلاحاً Stack Underflow گفته می‌شود. از طرفی اگر تعداد کاراکتر های وارد شده کاربر بیش از حد مورد انتظار ما باشد، برنامه دچار خطا می‌شود و به این چالش اصطلاحاً Stack Overflow گفته می‌شود.

همچنین برنامه نویس باید مراقب باشد که متغیرهای محلی به فضایی بیشتر از اندازه پشته (معمولا در پیاده سازی اکثر کامپایلر ها حدود 2 مگابایت است) نیاز نداشته باشند.

چالش سوم

تابع بازگشتی : نسخه های متعددی که در پشته نگهداری می شود که در نهایت باعث بروز خطای سرریز پشته می شود.

به تابع بازگشتی زیر توجه کنید.

int f()

{

f();

return 1;

}

این برنامه همواره خودش را صدا می‌زند و باعث می‌شود حافظه پشته پر شود.

اما سوالی که پیش می‌آید این است که این چالش ها و تعریف متغیر ها نیاز های روزمره ما در برنامه نویسی است. راه حل چیست؟

راه حل

برای حل مشکلات مطرح شده لازم است تا به سراغ dynamic memory allocation برویم.

ساختار حافظه در برنامه ها

در قسمت اول مقاله به توضیح سه قسمت اول (پایینی) پرداختیم. اکنون به تشریح قسمت چهارم یعنی هرم (heap) می‌پردازیم.

  • قسمت چهارم مربوط به بخش هرم یا heap است.
  • این قسمت از حافظه محدودیت خاصی ندارد و تا جایی که سیستم عامل و سخت افزار اجازه بدهد می‌تواند گسترش یاد.
  • برنامه نویس به هر مقدار که می‌خواهد می‌تواند از قسمت هرم (heap) حافظه بگیرد.
  • البته این کار باید توسط دستورالعملهای مخصوص و بطور صریح (explicit) انجام شود.
  • آزادسازی حافظه نیز باید توسط خود برنامه نویس انجام شود.

تخصیص حافظه در heap می‌تواند کار ساده‌ای باشد. ما یک نشانگر (pointer) را در اولین مکان آزاد در heap می‌گذاریم، بلوک درخواست شده را از آنجا اختصاص می دهیم و نشانگر را به مکان آزاد بعدی می‌بریم.

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

اگر بخواهیم بلوک های حافظه خالی شوند، یک سوال جدید پیش می‌آید و آن این است که "چه کسی این وظیفه را دارد؟"

برنامه نویس؟؟

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

بسیاری از برنامه نویسان با این آزادسازی صریح (explicit) حافظه، مشکلات جدی را تجربه کرده اند.

آزاد کردن غلط خیلی زود حافظه منجر به ایجاد یک اشاره گر آویزان (dangling pointer) می شود.

در قسمت های بعدی به ادامه مطالب می‌پردازیم.

موفق باشید.

منبع: Modern Compiler Design by Dick Grune, Kees van Reeuwijk, Henri E. Bal, Ceriel J.H. Jacobs, Koen Langendoen
https://vrgl.ir/At9II
مدیریت حافظهmemory managementmemory management in compiler designمدیریت حافظه در طراحی کامپایلر ها
دانشجوی مهندسی کامپیوتر | NET Developer.
شاید از این پست‌ها خوشتان بیاید