مدیریت حافظه مبتنی بر منطقه

در علوم رایانه، **مدیریت حافظه مبتنی بر ناحیه** نوعی از مدیریت حافظه است که در آن هر شیء تخصیص‌یافته به یک ناحیه نسبت داده می‌شود. یک ناحیه، که آن را یک **تقسیم‌بندی**، **زیراستخر**، **منطقه**، **عرصه،** **ناحیه**، یا **زمینه حافظه** نیز می نامند، مجموعه‌ای از اشیاء تخصیص‌یافته است، که می‌توانند به‌صورت یکجا و کارآمد، تخصیص مجدد یا آزادسازی شوند. تخصیص دهندگان حافظه‌ای که از حافظه مبتنی بر ناحیه بهره می‌برند، اغلب **تخصیص دهندگان ناحیه‌ای** نامیده می‌شوند، و زمانی که فقط با «جا به جایی» تنها یک اشاره گر کار کنند، به آنها **تخصیص‌دهنده‌های جهشی** گفته می‌شود.

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

در OC/360 و سیستم‌های پس از آن، این مفهوم در دو سطح اعمال می‌شود؛ هر کاری درون یک تقسیم‌بندی یا ناحیه پیوسته اجرا می‌شود. درخواست‌های مربوط به تخصیص حافظه یک زیراستخر را مشخص می‌کنند، و آن برنامه می‌تواند کل یک زیراستخر را آزاد کند. حافظه برای یک زیراستخر از ناحیه یا تقسیم بندی در بلوک‌هایی تخصیص می‌یابد که مضربی از ۲ کیلوبایت یا ۴ کیلوبایت هستند و عموما به صورت پیوسته قرار ندارند.

## نمونه
به عنوان مثالی ساده، کد C زیر را در نظر بگیرید که یک ساختار داده لیست پیوندی را تخصیص داده و سپس آن فضا حافظه را آزاد می‌کند:

```c
Region *r = createRegion();
ListNode *head = NULL;
for (int i = 1; i <= 1000; i++) {
    ListNode* newNode = allocateFromRegion(r, sizeof(ListNode));
    newNode->next = head;
    head = newNode;
}
// ...
// (use list here)
// ...
destroyRegion(r);
```
هرچند ساخت این لیست پیوندی به اعمال زیادی نیاز داشت، اما آزادسازی آن فضا سریع و تنها با یک دستور برای پاکسازی ناحیه ای که رئوس در آن قرار داشتند انجام شد. یعنی نیازی برای طی کردن تمام لیست نیست.

## پیاده‌سازی
نواحی صریح و ساده دارای پیاده سازی سرراستی هستند؛ شرح ذیل بر اساس کار هانسون است. هر ناحیه به عنوان یک لیست پیوندی از بلوک‌های بزرگ حافظه پیاده می‌شود؛ هر بلوک باید به حدی بزرگ باشد تا بتواند از چندین تخصیص پشتیبانی کند. بلوک فعلی دارای اشاره گری به سمت خانه آزاد بعدی در همان بلوک است، و زمانی که یک بلوک پر شود، بلوک دیگری تخصیص پیدا می‌کند و به لیست اضافه می شود. زمانی که این ناحیه آزاد شود، اشاره گر موقعیت-آزاد-بعدی به سمت ابتدای اولین بلوک باز می‌گردد، و این لیست از بلوک ها می تواند برای تخصیص بعدی مورد استفاده قرار گیرد. به روشی دیگر، زمانی که یک ناحیه آزاد می‌شود، این لیست از بلوک‌ها می‌تواند به یک لیست آزاد عمومی اضافه شود تا بعدا نواحی دیگری بلوک‌های این لیست را به خود اختصاص دهند. در هیچ کدام از این دو روش امکان آزادسازی تنها یک شیء موجود در ناحیه وجود ندارد.

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

## تاریخچه و مفاهیم
مفهوم پایه‌ای نواحی حافظه بسیار قدیمی است و نخستین بار در سال ۱۹۶۷ در بسته ذخیره‌سازی آزاد اِی‌ئی‌دی، ساخته داگلاس .تی .راس، ظاهر شد که در آن حافظه به سلسله‌مراتبی از مناطق تقسیم شده بود؛ هر منطقه تخصیص دهنده خود را داشت و می‌توانست به یکباره آزاد شود، به عبارتی این مناطق می توانستند به عنوان ناحیه مورد استفاده قرار گیرند. در سال ۱۹۷۶، استاندارد پی‌ال/1 مشمول نوع داده AREA شد. در سال ۱۹۹۰، هانسون نشان داد که نواحی صریح در C( که نام آنها را عرصه گذاشت) می‌توانستند به عملکرد زمانی به ازای هر بایت تخصیص‌یافته‌ دست یابند که حتی از سریع‌ترین مکانیسم‌های شناخته‌شده‌ی «تخصیص هرمی» نیز برتر بود. نواحی صریح ابزار مناسبی برای طراحی برخی از پروژه‌های نرم افزاری اولیه بر پایه زبان C بودند، از جمله وب‌سرور آپاچی، که نواحی آن را «استخر»، و سامانه مدیریت پایگاه داده PostgreSQL ، که نواحی آن را «زمینه حافظه» می‌نامند. مشابه تخصیص هرمی مرسوم، این طرح‌ها ایمنی حافظه را ارائه نمی‌دهند؛ برای یک برنامه نویس این امکان وجود دارد تا به ناحیه‌ای ، پس از آنکه آزاد شد، با استفاده از یک اشاره گر معلق دسترسی پیدا کند، یا اینکه آزاد کردن یک ناحیه را فراموش کند که موجب نشت حافظه می شود.

### استنتاج ناحیه
در سال ۱۹۸۸، محققین به تحقیق در مورد چگونگی استفاده از نواحی برای تخصیص امن حافظه پرداختند و مفهوم **استنتاج ناحیه** را معرفی کردند. مفهومی که در آن ایجاد و آزادسازی نواحی و همچنین انتساب «عبارت‌های تخصیص ایستا» به نواحی خاص، توسط کامپایلر در زمان کامپایل درج می‌شود. کامپایلر قادر است این کار را به گونه‌ای انجام دهد که تضمین کند اشاره گرهای معلق و نشت حافظه به وجود نیایند.

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

در سال ۱۹۹۴، این پژوهش در کار بنیادین توفته و تالپن تعمیم یافت تا چندریختی نوعی و توابع مرتبه بالا را در Standard ML، یک زبان برنامه نویسی تابعی، پشتیبانی کند؛ که این کار با استفاده از الگوریتم متفاوتی بر پایه استنتاج نوعی و مفاهیم نظری انواع نواحی چندریختی و حساب ناحیه‌ای انجام شد. کار آنها گسترشی از حساب لامبدا شامل نواحی را معرفی کرد و دو ساختار جدید به آن افزود:

اگر *e*1 در *p* بود : نتیجه علامت *e*1 را محاسبه و آن را در ناحیه *p* ذخیره کن.

هرگاه ناحیه *p* در *e*2 تمام شد : یک ناحیه ایجاد کن و آن را به *p* پیوند بزن؛ *e*2 را ارزیابی و سپس ناحیه را آزاد کن.

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

این «حسابان لامبدا»ی توسعه‌یافته، به عنوان یک نمایش میانی طراحی شده بود که قابلیت اثبات ایمنی حافظه برای کامپایل برنامه‌های استاندارد اِم‌اِل به کد ماشین را داشت. اما ساخت مترجمی که بتواند برای برنامه‌های بزرگ نتایج مطلوب تولید کند، با محدودیت‌های عملی متعددی روبرو شد که نیازمند تحلیل‌های جدیدی از جمله مدیریت فراخوانی‌های بازگشتی، فراخوانی‌های دنباله‌دار (دم‌بازگشتی)، و حذف نواحی حاوی تنها یک مقدار بود. این کار در سال ۱۹۹۵ به اتمام رسید، و درون کیت ام ال ادغام شد، ورژنی از ام ال که به جای زباله روبی، برپایه تخصیص ناحیه ای بود. این کار اجازه مقایسه‌ای مستقیم بین این دو روش را در برنامه های آزمایشی با حجم متوسط می‌داد. نتایج این آزمایش‌ها، بسته به اینکه برنامه چقدر برای تخصیص ناحیه ای مناسب باشد، بسیار متفاوت بود (از ۱۰ برابر سریع تر تا ۴ برابر کند تر)؛ با این حال، زمان‌های کامپایل در مرتبه دقیقه بودند. در نهایت، کیت اِم‌اِل به برنامه‌های بزرگ مقیاس داده شد و دو چیز به آن اضافه شد : طرحی برای گردآوری‌های جداگانه ماژول‌ها ، و روشی که از ترکیب استنتاج ناحیه‌ای و زباله روبی ردیابی به دست آمد.

### تعمیم به محیط زبان‌های دیگر
به دنبال توسعه کیت ام ال، «نواحی» به محیط زبان های برنامه نویسی دیگر تعمیم داده شدند :

* افزونه‌های گوناگون زبان برنامه‌نویسی C:
** گویش ایمن C به نام سایکلون ، که در کنار ویژگی های دیگر بسیاری، پشتیبانی از نواحی صریح را بیشتر می‌کند، و تاثیر انتقال برنامه‌های موجود C به استفاده از آنها را ارزیابی می‌کند.
** افزونه‌ای برای C به نام RC پیاده سازی شد که از نواحی با مدیریت صریح استفاده، ولی همچنین از شمارش ارجاع روی نواحی استفاده می‌کند تا با اطمینان از اینکه هیچ ناحیه‌ای از حافظه به صورت دائمی آزاد نشود، بتواند ایمنی حافظه را تضمین کند. نواحی، سربار شمارش ارجاع را کاهش می دهند؛ به این دلیل که ارجاعات درون هر ناحیه، زمانی که دستخوش تغییر قرار گیرند، برای به روز شدن نیازی به شمارش ندارند. RC شامل یک سامانه نوع ایستا‌ی صریح برای نواحی است که به برخی از به روز رسانی های شمارش ارجاعات اجازه حذف شدن می‌دهد.
** محدودیتی روی C به نام Control-C برنامه‌ها را محدود به استفاده از نواحی (و تنها یک ناحیه در آن واحد) می کند، به عنوان بخشی از طراحی آن برای تضمین ایستای ایمنی حافظه.
* نواحی برای زیرمجموعه‌ای از جاوا پیاده سازی و به جزءی حیاتی برای مدیریت حافظه در جاوا بیدرنگ تبدیل شدند، که آنها را با انواع مالکیت ترکیب می‌کند تا کپسوله سازی (Encapsulation) را به نمایش گذارد و برسی‌های زمان اجرا روی آزادسازی نواحی را از بین برد. اخیرا، سامانه ای نیمه خودکار برای استنتاج نواحی در برنامه‌های جاوا بیدرنگ تعبیه شده معرفی شد، که یک تحلیل ایستا در زمان کامپایل، یک سیاست تخصیص ناحیه در زمان اجرا، و راهنمایی های برنامه نویس را با هم ترکیب می کرد. نواحی با رایانش بی‌درنگ سازگاراند، زیرا سربار آنها به طرز ایستایی قابل پیشبینی هستند، بدون پیچیدگی زباله روبی افزایشی.
* جاوا 21، «ای پی آی جاوا»ای را برای تخصیص و رهاسازی عرصه‌ها اضافه کرد. هدف اعلام شده از آنها، بهسازی ادغام ایمن با کتابخانه های محلی است تا از نشت حافظه JVM جلوگیری کرده و خطر خرابی حافظه JVM توسط کد محلی را کاهش دهد.
* آنها برای زبان های برنامه نویسی منطقی Prolog و  Mercury پیاده سازی شدند، که این کار با گسترش مدل «استنتاج منطقه‌ای» تافت و تالپین انجام گرفت تا از بازگشت به عقب(backtracking) و جداسازی‌ها(cuts) پشتیبانی کنند.
* مدیریت حافظه مبتنی بر ناحیه، در سرتاسر زبان برنامه نویسی موازی ParaSail استفاده می‌شود. به دلیل فقدان اشاره گرهای صریح در ParaSail، نیازی به شمارش ارجاع نیست.

## معایب
سامانه‌هایی که از نواحی استفاده می‌کنند ممکن است در جایی که نواحی قبل آزادسازی خیلی بزرگ شوند و دارای بخش زیادی از داده‌های بلا استفاده باشند، با مشکلاتی رو به رو شوند؛ این مشکلات معمولا «نشت» نامیده می‌شوند (هرچند این نواحی درنهایت آزاد می‌شوند). برای از بین بردن نشت‌ها ممکن نیاز به تجدید ساختار برنامه باشد، که معمولا با معرفی نواحی جدید با عمر کوتاه‌تر انجام می‌شود. دیباگ کردن این مشکلات خصوصا در سامانه هایی دشوار است که از استنتاج ناحیه‌ای استفاده می کنند، جایی که برنامه نویس باید الگوریتم استنتاج اصلی را درک کند، یا نمایش میانی پرجزئیاتی را مورد برسی قرار دهد، تا مشکل را تشخیص دهد. زباله روب‌های ردیابی در آزادسازی به موقع این نوع از داده‌ها و بدون تغییر خود برنامه، بهینه‌تر هستند؛ این یکی از دلایل موجه وجود سامانه‌های ترکیبی ناحیه/زباله روبی است. از آن طرف، اگر ارجاع ‌ها به داده‌هایی که هرگز استفاده نخواهند شد حفظ شوند، زباله روب‌های ردیابی هم می توانند نشتی‌های نامحسوسی نشان دهند.

مدیریت حافظه مبتنی بر ناحیه زمانی به بهترین صورت کار می کند که تعداد نواحی نسبتا کم و هر کدام محتوی اشیاء زیادی باشد؛ برنامه‌هایی که محتوی نواحی پراکنده زیادی باشند، تجزیه داخلی نشان خواهند داد، که منجر به هدر رفت حافظه و یک سربار زمان برای مدیریت ناحیه می‌شود. در اینجا هم، در حضور استنتاج ناحیه ‌ی، تشخیص این مشکل ممکن است دشوارتر باشد.

## روش‌های ترکیبی
همانطور که پیش تر اشاره شد، RC از ترکیبی از نواحی و شمارش ارجاع استفاده می‌کند که موجب محدود شدن سربار شمارش ارجاع می‌شود، با نوجه به اینکه ارجاعات درونی نواحی، زمانی که دستخوش تغییر قرار می‌گیرند، برای به روز شدن نیاز به شمارش ندارند. مشابه آن، بعضی روش های ترکیبی علامت گزاری-ناحیه وجود دارند که زباله روبی ردیابی و نواحی را با هم ترکیب می‌کنند؛ این کار با تقسیم هرم به نواحی متعدد، انجام یک پیمایش علامت‌گذاری-جارو که در آن تمام نواحی حاوی اشیاء زنده علامت‌گذاری می‌شوند، و سپس آزاد کردن هر ناحیه علامت گزاری نشده‌ای انجام می‌شود. این کارها برای بهینه ماندن، نیازمند یکپارچه سازی پیوسته هستند.

## ارجاعات

رده:مدیریت حافظه