mina mohammadi
mina mohammadi
خواندن ۱۰ دقیقه·۱ سال پیش

مدیریت حافظه در Net.

در این مقاله، کارکرد Garbage Collection در Net. و طریقه بهینه سازی مدیریت حافظه در #C و را بررسی می کنیم. برای ورود به دنیای تکنیک های پیشرفته، بهترین روش ها و مثال های کاربردی که درک Garbage Collection را برای شما ساده می کند و مهارت های توسعه نرم افزار شما را بهبود می دهد آماده باشید.

اهمیت مدیریت حافظه در #C

مدیریت حافظه یک جنبه حیاتی در پرفورمنس و پایداری هر برنامه ای است. مدیریت کارآمد حافظه تضمین می کند که برنامه شما به طور موثر از منابع استفاده می کند، از نشت حافظه جلوگیری می کند و احتمال خرابی یا کاهش سرعت را کاهش می دهد. در سی شارپ، مکانیسم Garbage Collection در Net. وظیفه مدیریت خودکار حافظه را بر عهده دارد و باعث تمرکز توسعه‌دهندگان بر روی نوشتن کد بدون نگرانی از مدیریت دستی حافظه می شود.


مروری بر Garbage Collection در Net.

درواقع، Garbage Collection، یا به اختصار (GC)، یک فیچر مدیریت حافظه است که توسط دات نت Run Time ارائه شده است که به طور خودکار حافظه را از اشیایی که دیگر استفاده نمی شوند بازیابی می کند. این به جلوگیری از نشت حافظه، بهبود پرفورمنس برنامه و به حداقل رساندن احتمال خطاهای out-of-memory کمک می کند. در این مقاله، نحوه کار GC در Net.، نحوه تعامل آن با کد سی شارپ و نحوه بهینه‌سازی عملکرد آن برای برنامه‌های خود را مورد بحث قرار خواهیم داد.


درک GC در Net.

بیایید با درک کاملی از چیستی و نحوه عملکرد Garbage Collection در اکوسیستم Net. شروع کنیم.

اصول Garbage Collection

چگونگی کارکرد Garbage Collection
کارکرد GC در Net. بر اساس مفهوم دسترسی پذیری اشیا است. یک شی در صورتی قابل دسترسی در نظر گرفته می شود که یک ارجاع مستقیم یا غیرمستقیم از اشیاء ریشه، مانند فیلدهای استاتیک، متغیرهای محلی، یا ثبات های CPU، به آن وجود داشته باشد. GC به صورت دوره ای اشیا غیرقابل دسترس را بررسی می کند و حافظه اشغال شده توسط آنها را بازیابی می کند.

{ MyClass obj = new MyClass(); // Object is created and referenced // ... obj = null; // Object is now unreachable and becomes a candidate for garbage collection }

نسل ها و عملکرد

درواقع، Garbage Collector دات نت از یک رویکرد نسلی برای بهبود عملکرد استفاده می کند. اشیا به سه نسل - 0، 1 و 2 - گروه بندی می شوند. اشیا جدید در ابتدا در نسل 0 قرار می گیرند. هنگامی که GC اجرا می شود، ابتدا اشیاء را از نسل 0 جمع آوری می کند. اگر یک شی از فرآیند جمع آوری زنده بماند، به نسل بعدی ارتقا می یابد. این رویکرد زمان صرف شده برای Garbage Collection را کاهش می دهد، زیرا اشیا با عمر طولانی کمتر در این فرایند جمع آوری قرار می گیرند.

الگوریتم های Garbage Collection

چندین الگوریتم در Garbage Collection وجود دارد. در اینجا به سه مورد رایج می پردازیم.

الگوریتم علامت گذاری و جارو کردن

این الگوریتم از دو فاز تشکیل شده است:

  • علامت گذاری: GC گراف شی را طی می کند، از اشیاء ریشه شروع می شود و همه اشیاء قابل دسترسی را علامت گذاری می کند.
  • جارو کردن: GC حافظه را جارو می کند، اشیاء بدون علامت (غیرقابل دسترسی) را حذف می کند و حافظه را آزاد می کند.

الگوریتم کپی

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

الگوریتم نسلی (Generational)

همانطور که قبلا ذکر شد، الگوریتم Generational اشیا را بر اساس سن آنها به نسل ها گروه بندی می کند. GC ابتدا جوان ترین نسل را هدف قرار می دهد و اشیایی که زنده می مانند به نسل های قدیمی تر معرفی می شوند. این رویکرد زمان Garbage Collection را با تمرکز بر اشیا تازه ایجاد شده که احتمال عدم دسترسی آنها زیاد است، کاهش می دهد.


مدیریت حافظه در #C

اکنون که Garbage Collection در Net. را فهمیدیم، بیایید ببینیم که چگونه با مدل مدیریت حافظه #C ارتباط دارد.

تخصیص و آزاد سازی حافظه

پشته در مقابل هیپ

سی شارپ حافظه را در دو ناحیه مجزا مدیریت می کند: پشته و هیپ. پشته برای ذخیره value type ها، پارامترهای متدها و متغیرهای محلی استفاده می شود، در حالی که هیپ برای ذخیره reference type ها (اشیاء) استفاده می شود. Garbage Collector مسئول مدیریت حافظه در هیپ است.

آشنایی با Value Type ها و Reference Type ها

در واقع، value type ها (به عنوان مثال، int، float، structs) مستقیماً در پشته ذخیره می شوند، در حالی که reference type ها (به عنوان مثال، کلاس ها، آرایه ها) در هیپ ذخیره می شوند. هنگامی که یک value type را اختصاص می دهید، یک کپی از مقدار ایجاد می شود، در حالی که اختصاص یک reference type، یک مرجع جدید به همان شی ایجاد می کند.

int a = 42; // Value type
int b = a; // Creates a copy of the value
b = 13; // 'a' remains unchanged

MyClass objA = new MyClass(); // Reference type
MyClass objB = objA; // Creates a new reference to the same object
objB.SomeProperty = 7; // Modifies the object shared by 'objA' and 'objB'

مدیریت خودکار حافظه

سی شارپ به طور خودکار تخصیص و آزادسازی حافظه را مدیریت می کند و از Garbage Collector برای مدیریت حافظه مورد استفاده توسط reference type ها استفاده می کند. به عنوان یک توسعه دهنده، لازم نیست نگران آزادسازی صریح حافظه باشید، زیرا GC آن را برای شما مدیریت می کند.

اینترفیس IDisposable

​مدیریت منابع مدیریت نشده

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

در واقع، IDisposable برای مدیریت حافظه منابع مدیریت نشده یا "Unmanaged Resources" است.

پیاده سازی اینترفیس IDisposable

برای پیاده سازی IDisposable، باید یک متد Dispose تعریف کنید که منابع مدیریت نشده را آزاد می کند و به صورت اختیاری، نهایی سازی را برای شی متوقف می کند.

توضیح تکمیلی:

اگر کد سرویس گیرنده (Client)، Dispose را فراخوانی کند، پاکسازی منابع هر چند وقت یکبار انجام می شود و نیازی به انجام مجدد در طی نهایی سازی نیست. فراخوانی SuppressFinalize در این شرایط به این معنی است که شی دیگر متحمل هزینه اضافی GC نهایی سازی نمی شود.

و اگر کلاس شما فقط از منابع مدیریت شده استفاده می کند، نهایی کننده کاملا غیر ضروری است: GC از هر گونه منابع مدیریت شده مراقبت می کند، اجازه دهید خود آن منابع درگیر این باشند که آیا به یک نهایی کننده مجدد نیاز دارند یا خیر. شما فقط در صورتی باید یک نهایی کننده را در کلاس خود در نظر بگیرید که مستقیماً منابع مدیریت نشده را مدیریت کند.

public class MyClass : IDisposable
{
private IntPtr _unmanagedResource;

public MyClass()
{
_unmanagedResource = // Allocate unmanaged resource
}

public void Dispose()
{
ReleaseUnmanagedResource(_unmanagedResource);
GC.SuppressFinalize(this);
}

~MyClass()
{
ReleaseUnmanagedResource(_unmanagedResource);
}
}

دستور using

دستور using به شما این امکان را می دهد که از یک شی IDisposable استفاده کنید و اطمینان حاصل می کند که متد Dispose زمانی که شی از محدوده خارج می شود فراخوانی می شود.

using (MyClass obj = new MyClass())
{
// Use 'obj' as needed
} // 'Dispose' is automatically called when the block is exited

بهینه سازی Garbage Collection در Net.

اکنون بیایید تکنیک هایی را برای بهینه سازی Garbage Collection و اطمینان از استفاده کارآمد از حافظه در برنامه های #C خود بررسی کنیم.

استفاده کارآمد از حافظه

ادغام اشیا (استخر اشیا)

ادغام اشیاء با استفاده مجدد از اشیا یک استخر، هزینه های ایجاد و تخریب مکرر اشیا را کاهش می دهد. هنگامی که یک شی مورد نیاز است، از استخر گرفته می شود و زمانی که دیگر مورد نیاز نیست، برای استفاده مجدد به استخر برگردانده می شود.

public class MyObjectPool
{
private readonly Stack<MyClass> _pool = new Stack<MyClass>();

public MyClass GetObject()
{
return _pool.Count > 0 ? _pool.Pop() : new MyClass();
}

public void ReturnObject(MyClass obj)
{
_pool.Push(obj);
}
}

کش کردن

کش کردن تکنیکی است که نتایج عملیات گران قیمت را ذخیره می کند و در صورت نیاز مجدداً از آنها استفاده می کند و نیاز به تخصیص مکرر اشیا و آزادسازی را کاهش می دهد.

public class MyCache
{
private readonly Dictionary<string, ExpensiveObject> () _cache = new Dictionary<string, ExpensiveObject>();


public ExpensiveObject Get(string key)
{
if (!_cache.TryGetValue(key, out ExpensiveObject value))
{
value = new ExpensiveObject();
_cache[key] = value;
}
return value;
}

کاهش تخصیص اشیا

به حداقل رساندن تخصیص اشیا می تواند به کاهش هزینه های Garbage Collection کمک کند. برخی از تکنیک ها برای رسیدن به این هدف عبارتند از:

  • استفاده از Value Type ها (structs) به جای Reference Type ها (کلاس ها) در صورت لزوم.
  • استفاده مجدد از اشیاء در صورت امکان، مانند استفاده از StringBuilder برای الحاق رشته ها.
  • اجتناب از تغییر اندازه مکرر collection ها با تعیین ظرفیت اولیه.

تنظیم دقیق Garbage Collection

تنظیمات GC

دات نت چندین تنظیمات را ارائه می دهد که می توانند برای بهینه سازی Garbage Collection برای نیازهای خاص برنامه شما پیکربندی شوند. برای مثال، می‌توانید بین حالت‌های workstation و سرور GC یکی را انتخاب کنید یا concurrent garbage collection را فعال یا غیرفعال کنید.

// Enable server GC in the app.config or web.config file
<configuration>
<runtime>
<gcServer enabled="true"/>
</runtime>
</configuration>

امکان Forced Garbage Collection

در برخی موارد، ممکن است بخواهید به صورت دستی Garbage Collection را فعال کنید. می توانید این کار را با استفاده از متد ()GC.Collect انجام دهید. با این حال، از این با احتیاط استفاده کنید، زیرا می تواند بر عملکرد تأثیر منفی بگذارد.

// Force a garbage collection pass
GC.Collect();

نظارت و تشخیص عملکرد GC

می توانید از شمارنده های عملکرد (performance counters) و ردیابی رویداد (event tracing) برای نظارت بر رفتار و عملکرد Garbage Collector استفاده کنید. این می تواند به شما در شناسایی مشکلات احتمالی و تنظیم دقیق تنظیمات Garbage Collection برنامه کمک کند.

// Retrieve the current memory usage
long memoryUsage = GC.GetTotalMemory(false);
Console.WriteLine("Memory usage: {0} bytes", memoryUsage);

بهترین روش ها برای Garbage Collection در Net.

بیایید بحث را با بیان برخی از بهترین روش‌ها را برای اطمینان از Garbage Collection و مدیریت حافظه کارآمد

در برنامه‌های #C جمع‌بندی کنیم.

نوشتن کدِ حافظه-کارآمد

جلوگیری از نشت حافظه

برای جلوگیری از نشت حافظه، اطمینان حاصل کنید که:

  • با پیاده سازی IDisposable، منابع مدیریت نشده را به درستی آزاد کنید.
  • مدیریت کننده های رویداد را زمانی که دیگر مورد نیاز نیستند حذف کنید.
  • از ارجاعات دایره ای و گراف اشیا بزرگ خودداری کنید.

به حداقل رساندن تخصیص هیپ اشیای بزرگ

تخصیص اشیاء بزرگ (85000 بایت یا بزرگتر) می تواند باعث مشکلات عملکرد شود، زیرا آنها در هیپ شی بزرگ (LOH) ذخیره می شوند. برای به حداقل رساندن تخصیص LOH:

  • از آرایه ها یا collection هایی با ظرفیت اولیه مناسب استفاده کنید.
  • استفاده از فایل های نگاشت شده به حافظه (memory-mapped) برای ساختارهای داده بزرگ را در نظر بگیرید.

استفاده صحیح از Finalizers و IDdisposable

از نهایی کننده ها (Finalizers) می توان برای آزادسازی منابع مدیریت نشده استفاده کرد، اما همچنین می توانند بر عملکرد تأثیر منفی بگذارند. از نهایی کننده ها به اندازه کافی استفاده کنید و IDisposable را در صورت لزوم پیاده سازی کنید.

ابزارهای پروفایل و نظارت

ابزارهای مختلفی برای کمک به نمایه کردن و نظارت بر میزان مصرف حافظه برنامه و عملکرد Garbage Collection در دسترس هستند:

شمارنده های عملکرد

مانیتور عملکرد ویندوز (PerfMon) چندین شمارنده عملکرد مرتبط با garbage collection، مانند «% زمان در GC» و «Gen 0 Collections/sec» ارائه می‌کند.

ابزارهای تشخیصی ویژوال استودیو

ویژوال استودیو شامل ابزارهای تشخیصی داخلی است، مانند ابزار استفاده از حافظه، که می‌تواند به شما در تجزیه و تحلیل میزان مصرف حافظه برنامه و رفتار Garbage Collection کمک کند.

ابزارهای شخص ثالث

چندین ابزار شخص ثالث برای نمایه سازی و نظارت بر برنامه های Net. وجود دارد، مانند JetBrains dotMemory و Redgate ANTS Memory Profiler.

نتیجه

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

کد نویسی مبارک!

برگرفته از

https://www.bytehide.com/blog/garbage-collection-dotnet

garbage collectionمدیریت حافظهdotnetسی شارپ
شاید از این پست‌ها خوشتان بیاید