مدیریت حافظه در سی شارپ
آشنایی با مدیریت حافظه در سی شارپ
در رابطه با مدیریت حافظه در سی شارپ میتوان گفت قسمت garbage collector زبان #C در مقایسه با زبان ++C کاملتر بوده و عملکرد بهتری برای کاربران به همراه دارد. بدین ترتیب میتوان بدون آنکه ترس و نگرانی از شیوه تخصیص و آزادسازی حافظه داشت به کدنویسی پرداخت.
البته در صورتی که عملکرد کدها برایتان مورد اهمیت میباشد، بهتر است اطلاعاتی در رابطه با نحوه مدیریت حافظه در سی شارپ از سوی محیط زمان اجرای NET. به دست آورید تا شاهد عملکرد بهتری باشید؛
در این مقاله قصد داریم برایتان انواع مقداری در برابر انواع ارجاعی را شرح دهیم و در رابطه با هر یک توضیحات لازم را ارائه نماییم. همچنین برایتان توضیحاتی در رابطه با این که منظور از گرد آوری زباله چیست ارائه کردهایم؛
انواع مقداری در برابر انواع ارجاعی
در NET. دو نوع متغیر وجود دارد و همین موضوع ارتباط مستقیمی با شیوه مدیریت حافظه خواهد داشت. Value types یا همان انواع مقداری دارای اندازههای ثابت بوده و مقادیری مثل int ،bool ،float ،double و غیره را شامل می شوند.
چنین مقادیری با مقدار ارسال میشوند، هنگام فراخوانی توابع مختلفی مثل (someFunction(int arg آرگومانهای آن نیز کپی شده و در مکان جدیدی از حافظه قرار گرفته میشوند.
انواع مقداری
در مبحث مدیریت حافظه در سی شارپ عموماً Value typeها در پشته ذخیره میشوند البته متغیرهای لوکال نیز در پس زمینه و در پشته ذخیره شده که در رابطه با آنها استثناهایی نیز وجود دارد. ( در موارد استثنایی آنها در Heap ذخیره میشوند )
نکته: در تمام موارد مکان حافظه که نوع مقداری در آن قرار دارد، شامل مقدار واقعی خود متغیر میباشد.
پشته به مکان خاصی از حافظه اطلاق میشود که به وسیله محتوای پیشفرضی مقداردهی شده و امکان بسط پیدا کردن دارد.
پشته یک ساختمان داده LIFO (ورودی آخر، خروجی اول) است که میتوان آن را مانند یک استوانه در نظر گرفت.
در واقع متغیرها یک به یک وارد فوقانیترین بخش این استوانه شده و هنگامی که از دامنه مورد نظر خارج میشویم NET. به سراغ استوانه مورد نظر رفته و متغیرها را یکی یکی از بالا حذف مینماید تا سرانجام به آخرین متغیر که در بخش زیرین استوانه قرار دارد، برسد.
در این الگوریتم متغیرهایی که دیرتر وارد شدهاند زودتر خارج میشوند؛
Static void main()
{
Int x=0;
Bool y= true;
Float z= 1.25f
}
Stack(LIFO)= Z : 1.25f
Y : true
X : 0
پشته
سرعت پشته بسیار بالا بوده و اگرچه روی RAM قرار دارد اما مکان خاصی روی حافظه کش cpu محسوب نمیشود. جالب است بدانید که پشته بسیار کوچکتر از هیپ بوده و به همین دلیل قرار گرفتن آن روی کش امکانپذیر است. در صورت انجام این روند شاهد عملکرد بهتری از آن خواهیم بود.
مدیریت حافظه در سی شارپ و عملکرد خوب پشته به لطف ساختمان LIFO به دست آمده است. وقتی یک تابع فراخوانی میشود، تمامی متغیرهایی که برای آن تابع تعریف شدهاند به پشته افزوده میشوند و زمانیکه تابع بازگردانده میشود، متغیرها نیز از آن دامنه خارج میشوند.
بدین ترتیب پشته تمام مواردی که تابع در آن قرار داده بود را پاک نموده و مدیریت انجام این چرخه در زمان اجرا توسط قابهای پشته به انجام میرسد که وظیفه آنها تعریف بلوکهای حافظه برای پیشبرد عملکردهای مختلف میباشد. سرعت تخصیصهای پشته بسیار بالاست، چرا که صرفاً یک مقدار منفرد در انتهای قالب پشته نوشته میشود.
StackOverflow یکی از خطاهای مربوط به سرریز شدن پشته است. این خطا زمانی مشاهده میشود که تابع فراخوانی، متدهای ببسیار پیچیده و زیادی را در خود جای داده و باعث پر شدن پشته شود.
انواع ارجاعی
برخلاف انواع مقداری، اندازه انواع ارجاعی بسیار بزرگ بوده و نمیتوان مقیاس ثابتی را برای آنها در نظر گرفت. انواع ارجاعی مدت زمان زیادی روی پشته باقی مانده و اغلب آنها دادههایی هستند که به صورت شی و کلاسهای مختلف وهلهسازی شدهاند، (البته شامل آرایهها و رشتههایی که اندازه متغیری دارند، نمیشوند)
همانطور که کلاسها با کلیدواژه new قابل مقداردهی میباشند انواع ارجاعی نیز به همین ترتیب مقدار میگیرند و یک وهله جدید از کلاس میسازند و ارجاعی به آن بازگشت میدهد. همچنین می توان آن را به یک متغیر لوکال که برای ذخیرهسازی ارجاع به مکانی از هیپ استفاده می کند، نسبت داد;
هیپ میتواند بسط پیدا کرده و تا جایی که حافظه رایانه امکان میدهد گسترش پیدا کند به همین خاطر برای ذخیرهسازی دادههای حجیم گزینه مناسبی محسوب میشود.
البته این نکته نیز قابل ذکر است که هیپ سازمان نیافته است و در #C باید با یک garbage collector ، کنترل و مدیریت شود تا عملکرد خوبی از خود نشان دهد. تخصیصهای هیپ به اندازه کافی سریع هستند اما به طور قطع تخصیصهای پشته از سرعت بیشتری برخوردار هستند.
انواع پشته و انواع هیپ
به انواع مقداری، انواع پشته نیز گفته میشود و به انواع ارجاعی میتوان انواع هیپ را اطلاق کرد. اگرچه چند قاعده مستثنا نیز در این باره وجود دارد. برای مثال؛
• متغیرهای بیرونی تابعهای لامبدا و متغیرهای لوکال بلوکهای IEnumerator روی هیپ ذخیره میشوند.
• متغیرهای لوکال متدهای async نیز روی هیپ ذخیره میشوند.
• استراکتهای سفارشی انواع مقداری هستند، اما میتوانند شامل انواع ارجاعی از قبیل لیستها و رشتهها نیز باشند که اغلب روی هیپ ذخیره میشوند.
• همچنین فیلدهای کلاس استاتیک هم روی هیپ ذخیرهسازی میشوند.
•در قاعده فوق میتوان مهمترین موردی که جز استثنائات است را استفاده از stackalloc با <Span<T دانست. زیرا بلوکی از حافظه را به طور دستی به آرایهای موقت تخصیص میدهد.
زمانی که این پشته از دامنه خارج شود، مثل یک پشته عادی با آن رفتار شده و از حافظه پاک خواهد شد. به همین دلیل یک تخصیص هیپ پرهزینه دور زده میشود و روی garbage collector فشار کمتری اعمال میشود.
اگر چه این روند بهرهوری را افزایش می دهد اما به عنوان یک قابلیت پیشرفته باید برای اجرای هرچه بهتر آن و آشنایی با نحوه اجرای آن تخصص داشته باشید تا موجبات بروز استثنای سرریز پشته فراهم نشود.
منظور از گردآوری زباله چیست؟
پشته را میتوان یک ساختمان دادهای منظمی تلقی کرد در حالیکه هیپ چنین نمیباشد. در صورتی که هیپ برای مدیریت، ابزار مشخصی نداشته باشد به طور خودکار چیزی از روی آن پاک نمیشود و همین شرایط موجبات کمبود حافظه را به وجود آورده و اپلیکیشن به خوبی اجرا نخواهد شد. چون در واقع حافظهای آزاد نشده است.
بهکارگیری ابزارهای خاصی به نام گردآوری زباله برای مدیریت حافظه در سی شارپ به همین دلیل مورد استفاده قرار میگیرند. این ابزار روی نخ پسزمینه به طور دورهای اجرا میشود و نرمافزار را برای یافتن ارجاعهایی که دیگر روی پشته وجود ندارند اسکن میکند.
در این شرایط مشخص میشود که برنامه کدام دادههای ارجاعی را نیاز ندارد و برای آنها اهمیتی قائل نیست. محیط زمان اجرای NET. این قابلیت را دارد که وارد حافظه شده و آن را پاکسازی نماید یا آن را روی پردازش دیگری جابجا نماید تا هیپ منظمتر به کار خود ادامه دهد.
البته باید بدانید که فرایند گردآوری زباله پرهزینه بوده و اگرچه روی نخ پس زمینه این پردازش قابل اجرا است اما در شرایطی ممکن است فرایند اجرای برنامه متوقف شود و دلیل آن نیز اجرای پروژه گردآوری زباله میباشد.
در واقع همین اتفاق هزینهای است که از برنامه نویسی در #C ناشی میشود و بهترین کار این است که تولید زباله ها را کاهش دهیم.
زبانهای فاقد Garbage Collector
استفاده از زبانهایی که فاقد Garbage Collector هستند شما را مجاب میکند که به صورت دستی حافظههای تخصیص یافته را آزاد نمایید، این کار برای برنامهنویس کمی سخت است اما سرعت بیشتری را حاصل می کند.
مدیریت حافظه در سی شارپ مبحثی است که برای کسب تخصص کافی در آن باید با اصطلاحاتی مثل انواع ارجاعی و انواع مقداری آشنایی داشته باشید و از طرفی مفهوم گردآوری زباله و آزاد سازی حافظه را نیز بیاموزید. امیدواریم با مطالعه مقاله فوق اطلاعات لازم را کسب نموده باشید.