يقدم Visual Basic .net انعطافة جديدة في إدارة المصادر. حيث يوفر الـ CLR تقنية لإدارة المصادر تعرف باسم جمع النفايات Garbage Collection وذلك لتحرير المطور من معظم مهام إدارة الذاكرة. ولكن هذا لا يأتي بدون ثمن ولا يحررك بشكل كامل من التعامل مع إدارة الذاكرة. ففي بعض الحالات يجبرك جامع النفايات على أن تكون مدركا أكثر بخصوص العناصر التي يجب أن تقوم بالتخلص منها يدويا والتأكد من أن المصادر قد تم تحريرها بطريقة مناسبة. ولكن في أغلب الحالات لن تضطر للقلق حول متى يتم تدمير الأشياء.
في Visual Basic 6.0 عندما تصبح جميع المتغيرات التي تشير إلى شئ Object معين معينة إلى Nothing عندها يتم تحرير الذاكرة المرتبطة بهذه المتغيرات بشكل فوري. ويأخذ الـ CLR الآن هذه المسؤولية حول إدارة المصادر مما يمكن المطورين من التركيز على تحسين برامجهم عوضا عن كتابة الكثير من شيفرة إدارة الذاكرة.
وهذا يتطلب تغييرات في ممارسات كتابة الشيفرة. فمثلا عندما تضبط متغير ما إلى Nothing لا يتم تدمير الشئ Object مباشرة ولكن سوف يتم تدميره لاحقا وهذا ما يحدده جامع النفايات. وفي أغلب الحالات لا يجب أن يؤثر هذا على تطبيقك ولكن في بعض الحالات كبرنامج يقع تحت ضغط قلة مصادر النظام المتاحة يمكن أن يشكل معضلة حقيقية من ناحيتي الأداء والمرونة. ففي الحالات التي يكون فيها الأداء أساسي يكون من أول اهتماماتك إفراغ مصادر النظام فور فراغك من استخدامها.
أبق في ذهنك أن دورات جامع النفايات مكلفة. والفكرة تكمن في منع جامع النفايات من العمل بشكل متكرر كثيرا فكلما قمت بالتنظيف خلفك كلما تركت عمل أقل لجامع النفايات لعمله وبذلك تقوم بتحسين أداء برنامجك.
جامع النفايات The Garbage Collector
إذا كان التطبيق يستخدم مصادر غير مدارة Unmanaged Resources كتحديد ذاكرة خاصة أو مؤشرات الملفات أو عناصر أخرى من مصادر النظام فإن جامع النفايات في العادة لن يكون لديه فكرة عن كيفية تحرير تلك المصادر وبالرغم من أنه قد يكون قادرا على التعامل مع بعض هذه المصادر وربما لن يكون من الضروري تفريغهم بشكل دوري. ومن الهام أن تقوم ببعض التنظيف اليدوي وخاصة عندما تتعامل مباشرة مع ما يمثل بعض المصادر على الجهاز.
تجاوز Override الطريقة Object.Finalize وحرر بعض المصادر هناك ففي الحالة الافتراضية هذه الطريقة لا تفعل شيئا ولكن انتبه بما أن جامع النفايات يعمل باستخدام الطريقة Finalize فإن ذلك سيؤثر على الأداء فلا تقم باستخدامها إلا إذا كنت حقا بحاجة لاستخدامها. وحتى عندما يتم تجاوز Override الطريقة Finalize وتحرير المصادر لا يمكنك التحكم بمتى يقوم جامع النفايات ببدء عملية الجمع. مع أنه يمكنك دوما استدعاء System.GC.Collect ولكن لا يجب عليك القيام بذلك في بيئة الإنتاج. فإدارة مصادر CLR عملية معقدة والجامع يعرف متى يكون الوقت الأنسب لبدء دورة الجمع. كما أن أداء تطبيقك سيتأثر بشكل سئ إذا بدأت باستدعاء System.GC.Collect بشكل متكرر وأبق في ذهنك أن جامع النفايات يبدأ عندما يكون هناك حاجة لذاكرة مدارة وليس لديه تحكم حقيقي بالمصادر غير المدارة. حيث توفر لك الـ Framework حلا لهذه المشكلة وهي الواجهة IDisposable
الواجهة IDisposable
إذا كيف يمكنك معرفة إذا كان الشئ Object يحتاج إلى تنظيف إضافي؟ في الحقيقة الجواب سهل جدا فجميع الفئات Classes التي تقوم بتخصيص مصادر يجب تفريغها مباشرة يحب عليها أن تحقق الواجهة IDisposable وهي تحتوي على طريقة وحيدة
Public Interface IDisposable Sub Dispose() End Interface
إذا كانت الفئة Class التي تستخدمها تحقق هذه الواجهة يجب عليك استدعاء Dispose عندما تنتهي منها. أمر بسيط أليس كذلك؟ ولكن ما هي الفوائد من الواجهة IDisposable؟ الواجهة IDisposable تجعل من الممكن تحديد جميع الفئات Classes التي تخصص مصادر ثمينة وهي توفر آلية مبسطة يمكن الاعتماد عليها لتحرير جميع هذه المصادر. وكما ذكرنا سابقا العديد من الفئات في الـ Framework تحقق الواجهة IDisposable وهذا مثال يستخدم الفئة SqlConnection
Dim conn As New SqlConnection() ' Do Stuff conn.Dispose()
ولكن ليس بالضرورة أن يكون هذا موثوقا فحدوث الأخطاء والاستثناءات متوقعا دائما لهذا يجب وضع استدعاء Dispose في قسم Finally في حلقة Try … Catch مما يضمن أن شيفرتك ستقوم بالتنظيف دائما حتى عند حدوث خطأ أو استثناء ما وبذلك يمكن إعادة كتابة الشيفرة السابقة بالشكل
Dim conn As SqlConnection Try conn = New SqlConnection() ' Do Stuff Catch ex as Exception ' Handle Exception Here Finally conn.Dispose() End Try
ولكن ماذا إذا احتجنا لتحقيق الواجهة IDisposable؟
تحقيق الواجهة IDisposable
إليك سؤال مثير للاهتمام: متى يجب على الفئة أن تحقق الواجهة IDisposable؟ هذه ثلاث حالات عامة يجب عليك فيها تحقيق الواجهة IDisposable في فئتك:
• عندما تحتوي فئتك على فئات أخرى تحقق الواجهة IDisposable
• عندما تحتوي فئتك على واجهات لأشياء COM
• عندما تحتوي فئتك على مقبض Handle لمصادر Win32 فعالة
وأبسط تحقيق للواجهة IDisposable يمكن أن يكون على الشكل
Public Class MyDisposableClass Implements IDisposable ' Other members Public Overloads Sub Dispose() Implements IDisposable.Dispose ' Release Your Resources Here End Sub End Class
ولكن أبسط تحقيق لا يكون دائما الأكثر وثوقية. ويمكن أن يبدو تحقيق أكثر اكتمالا على الشكل
Public Class MyDisposableClass Implements IDisposable Public Overloads Sub Dispose() Implements IDisposable.Dispose Dispose(True) GC.SuppressFinalize(Me) ' No need call finalizer End Sub Protected Overridable Overloads Sub Dispose(ByVal disposing As Boolean) If disposing Then ' Free managed resources End If ' Free unmanaged resources End Sub Protected Overrides Sub Finalize() Dispose(False) End Sub End Class