بررسی CLR
دوشنبه 13 آذر 1391 8:24 AM
بررسی و آشنائی با محيط زمان اجرای دات نت يعنی CLR و ويژگيهای آن از جهت انتقال برنامه ها، بحث نسخه و مديريت حافظه
CLR يا Common Language Runtime در مرکز NET platform. واقع شده است. در حقيقت CLR عملی را که runtime ها در زبان های پيشين انجام می داند انجام می دهد. برای مثال ويژوال بيسيک 6 دارای يک Runtime مخصوص به خود بود که کارهای مديريت حافظه، فراخوانی فايلها و از اين دست اعمال را برای برنامه های بيسيک انجام می داد، همچنين ويژوال سی نيز دارای چنين ابزاری بود. CLR يک runtime مشترک است برای تمامی زبانهايی که بر مبنای NET. طراحی شده اند.
نسخه
در ويژوال بيسيک 6 و کلا ً سيستم های قبلی که بر COM استوارند نسخه يک COM مساله بزرگی برای انتشار آن است. در حالی که شما می توانستيد نسخه های مختلفی از يک COM داشته باشيد ولی در استفاده از ProgID ها دارای محدوديت بوديد. برای مثال در ويژوال بيسيک هنگام استفاده از Word.Application نمی توانستيد نسخه آن را انتخاب کنيد، يعنی برای مثال Word.Application.9. در CLR تمام اجزا در GAC يا Global Assemblies Cache بار می شوند. بعبارت ديگر اطلاعات اسمبلی ها در GAC قرار می گيرند. در CLR دو ويژگی برای اسمبلی هايی که در GAC قرار می گيرند وجود دارد:
Side-by-side versioning: بدين معنی که نسخه های مختلف يک اسمبلی در کنار هم بدون تداخل وجود دارند.
Automatic QFE: اگر نسخه جديدی از يک اسمبلی که با نسخه قبلی سازگاری دارد در GAC قرار گيرد، CLR اين مساله را تشخيص می دهد و از آن لحظه به بعد از نسخه جديد استفاده می کند.
نسخه ها در CLR از چهار قسمت Major.Minor.Revision.Build تشکيل شده اند. اگر در Major و Minor تغييری داده شود، اين بدين معناست که اين نسخه از اسمبلی ديگر با نسخه های قبلی سازگاری ندارد.
انتقال
برنامه هايی که به زبان ويژوال بيسيک قديمی نوشته می شوند در هنگام انتقال به کامپيوترهای ديگر دچار مشکلات فراوان می شوند. تمامی اجزا بايد در رجيستری ثبت شوند. اگر نسخه جديدی ايجاد شود امکان دارد برنامه هايی که از نسخه قديمی استفاده می کردند را از کار بيندازد. ولی درNET. هم مساله نسخه ها تقريبا ً حل شده است و هم نحوه انتقال. کافی است در کامپيوتر مقصد NET Framework. نصب شده باشد. در اين صورت به راحتی با استفاده از دستور xcopy داس می توانيد برنامه خود را انتقال بدهيد!
شايان ذکر است که اين نوشته صرفا ً توضيح مختصری درباره هر کدام از قسمت های NET. می دهد و برای هر کدام از اين اجزا می توان يک مقاله مفصل نوشت.
مديريت حافظه
درباره مديريت حافظه CLR بيشتر در زمينه VB بحث می کنيم.
مديريت بهتر بر Garbage Collection:
Runtime در ويژوال بيسيک دارای سيستم خود کار برای Garbage Collection ها است. در ويژوال بيسيک 6، runtime به شکل خودکار منابع را از شئ هايی که ديگر توسط برنامه استفاده نمی شوند می گيرد. برای مثال فرض کنيد می خواهيم يک فايل LOG ايجاد کنيم، برای اين کار می توان از دو شئ Scripting.Stream و Scripting.FileSystemObject استفاده کرد. اگر اين دو شئ را در تابعی به کار ببريم، بعد از اتمام عمليات، runtime منابع اختصاص داده شده به اين دو شئ را می گيرد. اما مواردی وجود دارد که runtime به آسانی امکان تشخيص شئ و زمان بلااستفاده بودن آن را ندارد.
Cyclical References:
يکی از مهمترين زمانهايی که runtime مربوط به VB نمی تواند تشخيص بدهد که آيا يک شئ به منابعی احتياج دارد يا اينکه کارش به پايان رسيده زمانی است که در متن برنامه حالتی به نام Cyclical Reference بوجود بيايد. به عنوان مثال اگر شئ A به صورت reference از شئ B استفاده کند و همچنين شئ B از A.
هر شئ COM مسئول نگهداری تعداد دفعاتی است که فعال شده است. بدين صورت که هر بار از روی آن ساخته شود با AddRef و هربار که يک برنامه آن را رها کند با Release از IUnKnown interface شمارنده ای را يکی افزايش يا کاهش می دهد. اگر آن شمارنده به صفر برسد شئ تمامی منابع خود را آزاد می کند، اما اگر هنگامی که يک شئ COM غير فعال شود ولی از Release استفاده نشود يک شئ بلا استفاده در حافظه می ماند.
runtime مربوط به VB 6 اين کار را به صورت خودکار انجام می دهد، اما هنگامی که دو شئ به هم اشاره می کنند بحث فرق می کند و runtime به شکل حالت ساده نمی تواند يک شئ را از حافظه بردارد. برای مثال به قطعه برنامه زير توجه کنيد.
'Class : CCyclicalRef
Dim m_objRef as Object
Public Sub Initialize(objRef as Object)
Set m_objRef = objRef
End Sub
Private Sub Class_Terminate()
Call Msgbox("Terminating.")
Set m_objRef = Nothing
End Sub
در کلاس CCyclicalRef متدی با نام Initialize تعريف شده است که در پارامتر های خود يک شئ را می پذيرد و از روی آن يک شئ ديگر می سازد. حال از کلاس تعريف شده در کد زير استفاده می کنيم.
Dim objA as New CCyclicalRef
Dim objB as New CCyclicalRef
Call objA.Initialize(objB)
Call objB.Initialize(objA)
Set objA = Nothing
Set objB = Nothing
ابتدا دو نمونه از روی کلاس CCyclicalRef با نامهای objA و objB ساختيم، حال هر دوی اين شئ ها يک بار ساخته شده اند و شمارنده آنها يک است. با استفاده از متد Initialize هر دوی شئ ها، آدرس حافظه يکديگر را مبادله می کنند و به اين شکل از روی هر دوی آنها يک بار ديگر ساخته می شود و شمارنده هر دو، 2 می شود. شماره يک مربوط به خود برنامه است و شماره دوم مربوط به شئ هايی که به هم اشاره می کنند. سپس هر دوی آنها را برابر nothing قرار می دهيم تا آنها را از حافظه حذف کنيم. در اينجا شمارنده هر دو يکی کم و برابر يک می شود. بنابراين برنامه terminate شده است ولی هنوز شئ در حافظه وجود دارد.
Garbage Collector در CLR:
روش Garbage Collector در CLR با VB 6 Runtime تفاوت دارد. در روش جديد که خود ِ CLR و GC مسئول اجرای آن هستند، آخرين باری که از nothing استفاده می شود ولی هنوز شئ در حافظه مانده باشد، GC اين وضعيت را درک می کند و آن شئ را بعد از مدتی از حافظه خارج می کند. شئ هايی هستند که مانند COM مسئول غير فعال کردن خود نيستند، GC آنها را نيز تشخيص داده و اگر برنامه ای ديگر از آنها استفاده نکند، از حافظه حذف می شوند.
Finalize:
GC متد Object.Finilize را قبل از اينکه هر شئ را از حافظه حذف کند صدا می زند. اين متد می تواند در هر زمانی بعد از اينکه برنامه ديگر از شئ استفاده نکرد صدا زده شود، لذا در هنگام استفاده از اين متد بايد نکته را در نظر گرفت. درNET. بهتر است قبل از اينکه يک شئ بوسيله nothing از بين برود از متد Dispose يا Close استفاده شود تا سريعا ً از حافظه حذف شود.
روش سريعتر تخصيص حافظه به شئ ها
هر زمان که يک برنامه يک شئ بسازد حافظه ای به آن اختصاص می يابد، آن حافظه در virtual memory است که برای هر برنامه اختصاص می يابد و به آن heap گفته می شود. CLR مفهومی به نام Managed Heap دارد بدين معنی که شئ ها را مديريت می کند و آنها را در يک Heap ِ مديريت شده قرار می دهد و CLR مسئول حفاظت آنهاست.
از مزايای اين روش اين است که راندمان سرعت اختصاص دادن حافظه بالا می باشد. به طور کلی وقتی کُد های مديريت نشده در Heap های مديريت نشده قرار می گيرند، به دنبال جايی در حافظه می گردند که بتوانند خود را در آن قرار دهند. در CLR شئای که ساخته می شود هميشه در بالای آخرين شئای که ساخته شده در heap قرار می گيرد. تصوير مربوطه را در اين آدرس مشاهده کنيد.
ابتدا CLR حافظه ای برای شئ های A، B و C بر روی Heap در نظر می گيرد. سپس شئ B از حافظه حذف می شود، در ادامه نيز برنامه يک شئ ديگری به نام D می سازد و آن را بر روی آخرين شئای که ساخته شده بود يعنی C قرار می دهد. اين روش برای اختصاص حافظه سريع است. اما اگر CLR به انتهای heap برسد چه عملی بايد انجام دهد؟ همان طور که مشاهده کرديد اين روش به شکل افزايشی شئ ها را در حافظه قرار می دهد. وقتی CLR ديگر نتواند از حافظه استفاده کند GC را فرا می خواند. GC هم فضاهايی مانند B را کاملا ً آزاد می کند و هم شئ ها را فشرده می کند و در پايين heap قرار می دهد تا بالای heap آزاد باشد.
خلاصه از کتاب Professional VB.NET از Wrox
مدیر تالار های: