حسین احمدی
بنیانگذار توسینسو و برنامه نویس و توسعه دهنده ارشد وب

مدیریت حافظه در سی شارپ بوسیله کلاس System.GC

در مقاله ای در باره مدیریت حافظه و نحوه کار Garbage Collector صحبت کردیم. اما مدیریت حافظه تنها اختصاص به CLR ندارد و برنامه نویسان هم می توانند در زبان های برنامه نویسی مانند سی شارپ و Visual Basic به سرویس های GC دسترسی داشته باشند.

دوره های شبکه، برنامه نویسی، مجازی سازی، امنیت، نفوذ و ... با برترین های ایران

برای یادگیری و آموزش سی شارپ ( آموزش زبان برنامه نویسی سی شارپ ) رایگان به این لینک بروید

این امر بوسیله کلاس System.GC امکان پذیر است. این کلاس در فایل mscorlib.dll قرار گرفته است. معمولاً، تنها زمانی باید از کلاس GC استفاده کنید از در داخل برنامه و کلاس ها از منابع Unmanaged استفاده کرده اید. برای مثال، استفاده از قابلیت COM Interop یا استفاده از قابلیت Platform Invoke در زبان سی شارپ. در ابتدا برخی از اعضاء کلاس GC را بررسی می کنیم:

  1. متد AddMemoryPressure و RemoveMemoryPressure: زمان فراخوانی GC کاملاً بستگی به مقدار حافظه اختصاص داده شده در Heap دارد. فرض کنید شئ ای داریم که مقدار کمی از حافظه Heap را در اختیار گرفته، اما داخل آن شئ مقدار زیادی از حافظه Unmanaged را استفاده کرده ایم. GC اطلاعی از حافظه Unmanaged تخصیص داده شده ندارد و تنها بر اساس حافظه Managed وارد عمل می شود. بوسیله این دو متد می تواند به CLR در مورد استفاده از حافظه Unmanaged اطلاع داد. به طور کلی زمانی که شئ ای در فضای Unmanaged قرار میگیرد، سایز آن را بوسیله این متد اطلاع رسانی کرده و بعد معمولاً در متد Finalize حذف آن را نیز مجدد بوسیله RemoveMemoryPressure اطلاع می دهند.
  2. متد Collect: بوسیله این متد می توان GC را به صورت دستی فراخوانی کرد. امکان آنتخاب Generation مورد نظر برای فراخوانی GC و همچنین حالت فراخوانی توسط GCCollectionMode که یک enum است وجود دارد.
  3. متد CollectionCount: می توان تعداد دفعات فراخوانی و مدیریت یک Generation توسط GC را توسط این متد بدست آورد.
  4. متد GetGeneration: شماره Generation مربوط به یک شئ را برای ما بر میگرداند.
  5. متد GetTotalMemory: فضای تخمینی اختصاص داده شده در حافظه Heap را برای ما بر میگرداند. می توان بوسیله یک پارامتر boolean مشخص کرد که محاسبه فضای اختصاص داده شده باید بعد از یکبار فراخوانی GC انجام شود یا خیر.
  6. خصوصیت MaxGeneration: تعداد Generation ها را بر می گرداند که در محیط دات نت تعداد آن ها 3 می باشد.
  7. متد SuppressFinalize: بوسیله این متد می توان یک شئ را برای جلوگیری از متد Finalize مشخص کرد.
  8. متد WaitForPendingFinalizers: اجرای Thread جاری را تا زمان اجرای متد Finalize تمام اشیاء Finalizable متوقف می کند. معمولاً این متد بعد از فراخوانی متد Collect فراخوانی می شود.

نمونه کد زیر، اطلاعاتی در مورد وضعیت حافظه Heap و همچنین اطلاعات مربوط به یک شئ به ما نمایش می دهد:

Console.WriteLine("Bytes on heap: {0}", GC.GetTotalMemory(false));
Console.WriteLine("Object Generations: {0}", (GC.MaxGeneration + 1));
Person person = new Person();
Console.WriteLine("Generation of person: {0}", GC.GetGeneration(person));

خروجی کد بالا به صورت زیر است:

Bytes on heap: 29868
Object Generations: 3
Generation of person: 0

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

  1. برنامه شما قصد اجرای بخشی را دارد که نباید توسط اجرای Garbage Collection وقفه ای در آن ایجاد شود.
  2. شما عملیات تخصیص حافظه برای تعداد زیادی شئ را انجام داده و تصمیم دارید در اولین فرصت عملیات حذف سایر اشیاء ای که مورد استفاده واقع نمی شوند را انجام دهید.

برای اجرای GC به صورت زیر عمل می کنیم:

GC.Collect();
GC.WaitForPendingFinalizers();

بعد از فراخوانی GC.Collect به یاد داشته باشید که حتماً متد WaitForPendingFinalizers رو اجرا کنید تا مطمئن شوید متد Finalizer تمامی اشیاء حذف شده از حافظه اجرا شده اند و با اجرای Finalizer ها وقفه ای در اجرای کدهای شما بوجود نمی آید. بوسیله متد Collect می توان شماره Generation را برای اجرا مشخص کرد:

GC.Collect(0);
GC.WaitForPendingFinalizers();

بوسیله کد بالا، عملیات پاک سازی بر روی Generation 0 انجام می شود. همچنین بوسیله Enum ای با نام GCCollectionMode نحوه اجرای GC را مشخص کنید که حاوی موارد زیر است:

  1. حالت Default: حالت Forced حالت پیش فرض است
  2. حالت Forced: به CLR می گوید که هم اکنون باید عملیات Collect اجرا شود.
  3. حالت Optimized: انتخاب زمان برای اجرا را به عهده CLR می گذارد تا بهرین زمان را برای اجرای Collect انتخاب کند.

در ادامه با یک مثال کاملتر مطلب خود را به پایان می رسانیم:

Console.WriteLine("Bytes on heap: {0}", GC.GetTotalMemory(false));
Console.WriteLine("Object Generations: {0}.", (GC.MaxGeneration + 1));
Person person = new Person();
Console.WriteLine("Generation of Person is: {0}", GC.GetGeneration(person));
object[] persons = new object[50000];
for (int i = 0; i < 50000; i++)
    persons[i] = new object();
GC.Collect(0, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
Console.WriteLine("Generation of person is: {0}",
GC.GetGeneration(person));
if (persons[9000] != null)
{
    Console.WriteLine("Generation of persons[9000] is: {0}",
    GC.GetGeneration(persons[9000]));
}
else
    Console.WriteLine("persons[9000] is no longer alive.");
Console.WriteLine("Gen 0 has been swept {0} times", GC.CollectionCount(0));
Console.WriteLine("Gen 1 has been swept {0} times", GC.CollectionCount(1));
Console.WriteLine("Gen 2 has been swept {0} times", GC.CollectionCount(2));
Console.ReadLine();

با اجرای کد بالا، خروجی زیر نمایش داده می شود، البته با هر بار اجرا احتمال تغییر در خروجی ممکن است:

Bytes on heap: 38060
Object Generations: 3.
Generation of Person is: 0
Generation of person is: 1
Generation of persons[9000] is: 1
Gen 0 has been swept 1 times
Gen 1 has been swept 0 times
Gen 2 has been swept 0 times

در این مطلب با نحوه کار با کلاس GC و مدیریت حافظه در دات نت بشتر آشنا شدیم. امیدوارم این مطلب مورد توجه دوستان قرار گرفته باشد.

یادگیری برنامه نویسی برای متخصصین حوزه کامپیوتر این روزها یک الزام به حساب می آید. از جمله محبوب ترین زبان های برنامه نویسی دنیا می توانیم به زبان برنامه نویسی سی شارپ ، زبان برنامه نویسی جاوا ، زبان برنامه نویسی پایتون ، زبان برنامه نویسی سی پلاس پلاس و زبان برنامه نویسی SQL ( لازمه هر زبان دیگری ) و زبان برنامه نویسی PHP اشاره کنیم.

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


حسین احمدی
حسین احمدی

بنیانگذار توسینسو و برنامه نویس و توسعه دهنده ارشد وب

حسین احمدی ، بنیانگذار TOSINSO ، توسعه دهنده وب و برنامه نویس ، بیش از 12 سال سابقه فعالیت حرفه ای در سطح کلان ، مشاور ، مدیر پروژه و مدرس نهادهای مالی و اعتباری ، تخصص در پلتفرم دات نت و زبان سی شارپ ، طراحی و توسعه وب ، امنیت نرم افزار ، تحلیل سیستم های اطلاعاتی و داده کاوی ...

نظرات