اختصاص حافظه پویا در سی
اختصاص حافظه پویا در سی اشاره به انجام عمل اختصاص حافظه پویا در زبان سی با استفاده از گروهی از توابع در کتابخانه استاندارد سی به نامهای malloc, calloc, realloc و free دارد. پیادهسازیهای مختلفی از این توابع وجود دارد که در کارایی و زمان اجرا با هم تفاوت دارند.
زبان سی به سه روش حافظه را در اختیار برنامه قرار میدهد.
- به صورت ایستا
- به صورت خودکار
- به صورت پویا
در حالت ایستا، متغیرها در تمام طول اجرای برنامه در حافظه باقی میمانند و وقتی اجرای برنامه به اتمام رسید فضای مورد استفاده آنها به سیستم پس داده میشود. (مانند متغیرهای سراسری برنامه). در حالت خودکار، متغیرها به کمک یک پشته به توابع اختصاص داده میشوند و هر وقت که تابع فراخوانی میشود، متغیرها در پشته به وجود میآیند و هر وقت که اجرای تابع به اتمام رسید، حافظه آنها به سیستم پس داده میشود. در حالت ایستا و خودکار، اندازهای حافظه مورد نیاز در زمان کامپایل مشخص میشود. اگر حافظه مورد نیاز تا زمان اجرای برنامه مشخص نباشد (برای مثال وقتی که قرار است فایلی با یک اندازه دلخواه توسط کاربر از دیسک خوانده شود)، این روشها کارامد نخواهند بود.
عمر حافظه اختصاص داده شده هم مسئله دیگری است. هیچ یک از روشهای ایستا و خودکار برای همه موقعیتها مناسب نیستند. در حالت ایستا متغیرها چه استفاده شوند و چه استفاده نشوند در تمام مدت زمان اجرای برنامه در حافظه باقی میمانند. در روش اختصاص خودکار هم دادهها نمیتوانند در فراخوانی چندباره تابع در حافظه باقی بمانند. در خیلی از موارد برنامهنویس احتیاج به انعطاف بیشتری برای مدیریت عمر حافظه اختصاص یافته دارد.
این مشکلات با اختصاص حافظه به صورت پویا برطرف میشوند. اختصاص حافظه به صورت پویا حافظه را صریحتر از دو روش قبلی اما با انعظاف بیشتری مدیریت میکند. معمولاً این کار با اختصاص دادن حافظه از فضای هیپ (به انگلیسی: heap) (که به همین کار اختصاص یافته) انجام میشود. در زبان سی، از تابع کتابخانهای malloc برای اختصاص دادن یک بلاک از حافظه در هیپ به برنامه استفاده میشود. برنامه به این فضا از طریق اشارهگری که تابع malloc برمیگرداند دسترسی دارد. وقتی که کارمان با حافظه به اتمام رسید، اشاره گر مورد نظر برای تابع free ارسال میشود تا حافظه به سیستم برگردانده شود. سیستم میتواند از این حافظه برای اهداف دیگر استفاده کند.
مروری بر توابع
نام تابع | توضیح |
---|---|
malloc | یک مقدار مشخص از حافظه را به برنامه اختصاص میدهد. |
realloc | حافظهای که قبلاً اختصاص یافته را افزایش یا کاهش میدهد. ممکن است احتیاج باشد حافظه دوباره اختصاص یابد. |
calloc | مقدار مشخصی از حافظه را اختصاص میدهد. اما آنها را با صفر مقداردهی میکند. |
free | حافظه اختصاص یافته را آزاد میکند و به سیستم باز میگرداند |
تفاوت بین malloc و calloc
تفاوتهایی بین این دو تابع وجود دارد. اول اینکه malloc تنها یک آرگومان (مقدار فضای مورد نیاز بر حسب بایت) دریافت میکند. اما calloc به دو آرگومان احتیاج دارد. (تعداد متغیرها برای اختصاص، اندازه هر متغیر) دوم اینکه malloc حافظه اختصاص داده شده را مقدار دهی نمیکند و بنابراین اطلاعات تصادفی در آن قرار دارد. اما calloc حافظه اختصاص یافته را با عدد صفر پر میکند. بنابراین malloc سریعتر است اما calloc امنتر است. دستور calloc(number, size) معادل دستور malloc(number*size) است.
مثال
دستور زیر آرایه از ۱۰ عدد صحیح ایجاد میکند:
int array[10];
با این حال اندازه آرایه در زمان کامپایل مشخص میشود و ثابت است و در زمان اجرا نمیتواند تغییر کند. برای اختصاص دادن یک آرایه با اندازه مشابه به صورت پویا میتوان از این کد استفاده کرد:
/* Allocate space for an array with ten elements of type int. Some programmers place an optional "(int *)" cast before malloc. */
int * array = malloc(10 * sizeof(int));
/* Check if the memory couldn't be allocated; if it's the case, handle the problem as appropriate. */
if (NULL == array) {
/* Handle error… */
}
/* If we get here, allocation succeeded. Do work… */
/* We are done with the array, and can free (release) the block of memory. */
free(array);
/* Make sure the freed pointer isn't used anymore by assigning it to NULL (or another allocated memory region). */
array = NULL;
در صورتیکه malloc موفق نشود حافظه خواسته شده را اختصاص دهد، مقدار NULL را برمیگرداند.
malloc یک اشاره گر void برمیگرداند. بدین معنی که این اشاره گر به فضایی با نوع داده نامشخص اشاره میکند. در زبان سی++ باید با استفاده از عملگر cast این اشاره گر را به نوع داده مورد نیاز تبدیل کرد. اما در زبان سی به این کار احتیاج نیست.
پیادهسازیها
پیادهسازی فریبیاسدی و نتبیاسدی
در نسخههای قدیمی سیستمعاملّهای فریبیاسدی و نتبیاسدی از پیادهسازی phkmalloc استفاده میشد که توسط پل هنینگ کمپ انجام شده بود. اما در نسخه ۷/۰ فریبیاسدی و نسخه ۵/۰ نتبیاسدی پیادهسازی jemalloc جایگزین شد که توسط جیسون اونس انجام شدهاست. دلیل اصلی انجام این کار عدم انعطافپذیری phkmalloc در شرایط چند نخی بود.
منابع
مشارکتکنندگان ویکیپدیا. «C dynamic memory allocation». در دانشنامهٔ ویکیپدیای انگلیسی، بازبینیشده در ۹ ژوئیه ۲۰۱۳.