مدیریت حافظه در 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 typeint b = a; // Creates a copy of the valueb = 13; // 'a' remains unchangedMyClass objA = new MyClass(); // Reference typeMyClass objB = objA; // Creates a new reference to the same objectobjB.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 passGC.Collect();نظارت و تشخیص عملکرد GCمی توانید از شمارنده های عملکرد (performance counters) و ردیابی رویداد (event tracing) برای نظارت بر رفتار و عملکرد Garbage Collector استفاده کنید. این می تواند به شما در شناسایی مشکلات احتمالی و تنظیم دقیق تنظیمات Garbage Collection برنامه کمک کند.// Retrieve the current memory usagelong 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