در ادامه مطالب قبلی به این میپردازیم که چالش های موجود هنگام تخصیص حافظه به روش پشته چیست؟
دو چالش مهم در این روش وجود دارد که با مثال به تشریح آن ها میپردازیم:
فرض کنید شما قرار است به عنوان برنامه نویس برنامه ای بنویسید تا از کاربر نام و نام خانوادگی را دریافت کند. معمولا پیاده سازی این برنامه در زبان C به این صورت است که یک آرایه از نوع کاراکتر ایجاد میکنیم و لازم است تا مقداری برای آن در نظر بگیریم. چون ما از قبل اطلاعی درباره تعداد کاراکتر های نام و نام خانوادگی کاربر نداریم پس باید یک حد مناسبی از آن را در نظر بگیریم. مثلا طول آرایه را به اندازه 30 خانه مقدار دهی میکنیم. حال اگر تعداد کاراکتر های واردی نام و نام خانوادگی کاربر کمتر از 30 عدد باشد (مثلا 20 کاراکتر) ما 10 کاراکتر از مقدار حافظه ای که دریافت کرده ایم را هدر دادهایم (به این چالش اصطلاحاً Stack Underflow گفته میشود. از طرفی اگر تعداد کاراکتر های وارد شده کاربر بیش از حد مورد انتظار ما باشد، برنامه دچار خطا میشود و به این چالش اصطلاحاً Stack Overflow گفته میشود.
همچنین برنامه نویس باید مراقب باشد که متغیرهای محلی به فضایی بیشتر از اندازه پشته (معمولا در پیاده سازی اکثر کامپایلر ها حدود 2 مگابایت است) نیاز نداشته باشند.
تابع بازگشتی : نسخه های متعددی که در پشته نگهداری می شود که در نهایت باعث بروز خطای سرریز پشته می شود.
به تابع بازگشتی زیر توجه کنید.
int f()
{
f();
return 1;
}
این برنامه همواره خودش را صدا میزند و باعث میشود حافظه پشته پر شود.
اما سوالی که پیش میآید این است که این چالش ها و تعریف متغیر ها نیاز های روزمره ما در برنامه نویسی است. راه حل چیست؟
برای حل مشکلات مطرح شده لازم است تا به سراغ dynamic memory allocation برویم.
در قسمت اول مقاله به توضیح سه قسمت اول (پایینی) پرداختیم. اکنون به تشریح قسمت چهارم یعنی هرم (heap) میپردازیم.
تخصیص حافظه در 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