بررسی و آشنائی با محیط زمان اجرای دات نت یعنی 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 آزاد باشد.