مقدمه
در درس قبل با پروسههای سیستمعامل و نحوهی تعامل با آنها آشنا شدیم. یک پروسه، یک مرز
ایزولاسیون است که توسط سیستمعامل فراهم میشود؛ یعنی حافظه و منابع یک پروسه از پروسههای دیگر
کاملاً جداست. در دنیای .NET Framework (نسخههای قدیمیتر .NET)، یک واحد
ایزولاسیون سبکتر و مدیریتشده در داخل یک پروسهی واحد نیز وجود داشت که به آن
دامنهی برنامه (Application Domain) یا AppDomain
گفته میشد. درک مفهوم AppDomain برای فهم معماری تاریخی .NET و همچنین درک
دلیل تغییرات در .NET Core و نسخههای مدرنتر، بسیار مهم است.
AppDomain چیست؟
یک AppDomain را میتوان به عنوان یک "پروسه در پروسه" در نظر گرفت. این یک مرز منطقی و
ایزوله در داخل یک پروسهی سیستمعامل است که CLR آن را مدیریت میکند. در .NET
Framework، هر برنامه حداقل در یک AppDomain پیشفرض اجرا میشد، اما امکان
ساخت چندین AppDomain در یک پروسهی واحد وجود داشت.
اهداف اصلی AppDomain در .NET Framework
- ایزولاسیون (Isolation): کد در حال اجرا در یک AppDomain
نمیتوانست به طور مستقیم به کد یا دادههای یک AppDomain دیگر دسترسی پیدا کند. این
ویژگی بسیار مهم بود. برای مثال، یک وب سرور مانند IIS میتوانست هر وبسایت را در
AppDomain جداگانهی خود اجرا کند. به این ترتیب، اگر یک وبسایت به دلیل یک خطای
جدی از کار میافتاد، فقط AppDomain مربوط به خودش دچار مشکل میشد و روی دیگر
وبسایتهایی که در همان پروسه در حال اجرا بودند، تأثیری نمیگذاشت.
- بارگذاری و تخلیهی اسمبلیها (Loading and Unloading Assemblies): این
مهمترین کاربرد AppDomain بود. در .NET Framework، تنها راه برای
"تخلیه" (unload) یک اسمبلی (DLL) از حافظه، تخلیهی کامل AppDomainای بود که آن را
بارگذاری کرده بود. این برای سیستمهایی که نیاز به بارگذاری و حذف دینامیک پلاگینها داشتند،
حیاتی بود.
تغییر بزرگ: AppDomain در .NET Core و .NET مدرن
یکی از بزرگترین تغییرات معماری در گذار از .NET Framework به .NET Core (و
نسخههای بعدی مانند .NET 5/6/7/8)، مربوط به AppDomain بود.
در .NET مدرن، قابلیت ایجاد چندین AppDomain در یک پروسه حذف شده
است. هر برنامهی .NET اکنون تنها در یک AppDomain واحد اجرا
میشود و شما نمیتوانید دامنههای جدیدی بسازید.
چرا این قابلیت حذف شد؟
- پیچیدگی: پیادهسازی و مدیریت صحیح ایزولاسیون بین AppDomainها
بسیار پیچیده و هزینهبر بود.
- جایگزینهای بهتر برای ایزولاسیون: با ظهور تکنولوژیهایی مانند کانتینرها
(مثل Docker) و معماری میکروسرویس، الگوهای بهتری برای ایزولاسیون در سطح پروسهی سیستمعامل
فراهم شد که بسیار قویتر و استانداردتر هستند.
- جایگزین برای تخلیهی اسمبلیها: برای حل مشکل اصلی یعنی تخلیهی اسمبلیها،
.NET Core یک مکانیزم جدید و سبکتر به نام AssemblyLoadContext را معرفی کرد.
جایگزین مدرن: AssemblyLoadContext
در .NET مدرن، اگر نیاز به بارگذاری دینامیک اسمبلیها و سپس تخلیهی آنها از حافظه
دارید (مثلاً در یک سیستم پلاگین)، باید از AssemblyLoadContext
استفاده کنید. این کلاس به شما اجازه میدهد تا یک محدودهی ایزوله برای بارگذاری اسمبلیها ایجاد
کنید. مهمترین ویژگی آن این است که میتوان آن را "قابل جمعآوری" (collectible) تعریف کرد.
Program.cs (Conceptual Example)
using System.Reflection;
using System.Runtime.Loader;
var loadContext = new AssemblyLoadContext("MyPluginContext", isCollectible: true);
Assembly pluginAssembly = loadContext.LoadFromAssemblyPath("Path/To/MyPlugin.dll");
loadContext.Unload();
با فراخوانی متد Unload، همهی اسمبلیهایی که در آن AssemblyLoadContext بارگذاری شدهاند، از
حافظه تخلیه میشوند و زبالهروب میتواند حافظهی آنها را بازپس گیرد. این مکانیزم، جایگزین اصلی
و مدرن برای قابلیت تخلیهی اسمبلیها در AppDomain است.
خلاصه و نتیجهگیری
- AppDomain در .NET Framework: یک واحد ایزولاسیون سبک در داخل یک پروسه بود که
برای جداسازی کد و تخلیهی اسمبلیها استفاده میشد.
- AppDomain در .NET Core/5+: هر برنامه فقط یک AppDomain دارد و
قابلیت ایجاد دامنههای جدید حذف شده است. این مفهوم دیگر برای ایزولاسیون به کار نمیرود.
- جایگزین مدرن برای ایزولاسیون: استفاده از پروسههای مجزای سیستمعامل یا
تکنولوژیهای کانتینرسازی مانند Docker.
- جایگزین مدرن برای تخلیهی اسمبلیها: استفاده از کلاس AssemblyLoadContext.
بنابراین، هرچند دانستن مفهوم AppDomain برای درک معماری .NET و کار با کدهای
قدیمیتر مفید است، اما در پروژههای جدید .NET، شما برای ایزولاسیون و مدیریت پلاگینها
از ابزارهای دیگری استفاده خواهید کرد.