.NET Garbage Collector(GC) and IDisposable Interface

Memory(RAM) ပမာဏတွေ နည်းနည်းလေပဲ သုံးတဲ့ ကွန်ပျူတာခေတ်ဦးတုန်းက program တွေရေးသားရာမှာ Memory ပေါ်မှာ Variables, Object တွေကို နေရာပေးဖို့ တော်တော်လေးကို စဉ်းစားရပါတယ်။ တကယ့်ကိုလိုအပ်မှပဲ Memory Object တွေကို သုံးပါတယ်။ အသုံးပြုပြီးရင်လည်း ဂရုတစိုက်နဲ့ Memory ပေါ်ကနေ ပြန်ဖြုတ်ချပေးရပါတယ်။ အခုခေတ်မှာတော့ Memory ပမာဏတွေလည်း ခပ်များများသုံးနိုင်လာသလို့ Memory Management နည်းပညာတွေဟာလည်း တိုးတက် လာပါတယ်။ ဒါပေမယ့် Programming Language တွေကြားမှာတော့ စိန်ခေါ်မှု တစ်ခုအဖြစ် ရှိနေတုန်းပါပဲ။

.Net မှာတော့ အဲဒီအတွက် Garbage Collector (GC) ကို မိတ်ဆက်ပေးထားပါတယ်။ Garbage Collector(GC) ဟာ Memory ပေါ်မှာ နေရာယူထားတဲ့ Object တွေကို နောက်ကွယ်ကနေ အမြဲ စောင့်ကြည့်နေပါတယ်။ တကယ်လို့ အဲဒီ Object တွေဟာ ဘာ Reference မှ မရှိတော့ရင် GC က အဲဒီ Object ကို Memory ပေါ်ကနေ ဖြုတ်ချလိုက်ပါတယ်။ နောက်ကွယ်ကနေ အလုပ်လုပ်နေတယ်ဆိုပေမယ့် Low Priority အဖြစ်ပဲရှိနေတဲ့အတွက် Performance အတွက် ပူစရာမလိုပါဘူး။ Managed Application (.Net Application) တွေအတွက်တော့ GC က သူ့အလိုအလျှောက်လုပ်ဆောင်ပေးမှာပါတယ်။ တကယ်လို့ Memroy တော်တော်များများ တပ်ဆင်ထားတဲ့ ကွန်ပျူတာမှာဆိုရင်တော့ GC က သူ့သတ်မှတ်ချက် မရောက်မချင်း object တွေကို Memory ပေါ်ကနေ ဖြုတ်ချပစ်မှာ မဟုတ်ပါဘူး။

Memory ပေါ်မှာ နေရာယူထားတဲ့ Object တွေကို ဘာ Reference မှ မရှိတော့ရင် GC က သူ့ အလိုအလျှောက် ဖြုတ်ချ လိုက်တယ်လို့ အပေါ်မှာ ပြောခဲ့ပေမယ့် ချက်ချင်း ဖြုတ်ချ လိုက်တာတော့ မဟုတ်ပါဘူး။ GC အတွက် Round Trip တကြိမ် အလုပ်လုပ်တဲ့ အချိ်န်ကျမှ Reference မရှိတော့တဲ့ Memory Object တွေကို စုပေါင်း ပြီတော့ ဖြုတ်ချလိုက်တာပါ။ Function,Method အတွင်းမှာ ကြော်ငြာခဲ့တဲ့ Variables, Objects တွေဟာ အဲဒီ Function,Method တွေ အပြင်ဘက်ရောက်သွားတာနဲ့ ဘာ Reference မှ မရှိတော့ပါဘူး။ Class level variables တွေအတွက်တော့ Nothing ဆိုတဲ့ စာလုံးနဲ့ assing လုပ်ပြီး Reference ကို ဖြုတ်ချပစ်ရမှာပါ။ (ဥပမာ MyCustomer=Nothing) အဲဒီလို Nothing assign လုပ်လို်က်တာနဲ့ GC က ဒီ Object ဟာ ဘာ Reference မှ မရှိတော့ဘူးလို့ နားလည်သွားပြီး အချိ်န်ကျတာနဲ့ Memory ပေါ်ကနေ ဖြုတ်ချ ပစ်မှာ ဖြစ်ပါတယ်။

Managed Application(.Net Application) တွေအတွက်တော့ GC ဟာ အဆင်ပြေသလိုပါပဲ။ ဒါပေမယ့် External Resources (Files,Database,Internet Connection,Windows Resources..) တွေကို ကိုယ့် Application က ယူသုံးထားရင်တော့ GC ကိုပုံအပ်လို့ မဖြစ်နိုင်တော့ပါဘူး။ GC ကလည်း အဲဒီလို External Resources တွေကို သူ့အလိုအလျှောက်မဖြုတ်ချနိုင်ပါဘူး။ အဲဒီ Expensive Resources တွေကျတော့ ကိုယ်တိုင်ကိုယ်ကျ Memory ပေါ်ကနေ ဖြုတ်ချပစ်တာ အကောင်းဆုံးပါပဲ။ ကံကောင်းထောက်မစွာနဲ့ပဲ GC က Object တွေကို ဖြုတ်ချတဲ့ အချိန်မှာ Finalize ဆိုတဲ့ Method ကို သွားခေါ်ပါတယ်။ အဲဒီ Method ထဲမှာ Extrernal Resources တွေကို ကိုယ်တိုင်ကိုယ်ကျ ဖြုတ်ချ ပေးရမှာပါ။ .Net မှာ Class တိုင်းဟာ System.Object ကို အမြဲတမ်း Inheritance လုပ်ပါတယ်။ Finalize Method ဟာ System.Object class ထဲမှာရေးထားပြီး Protected Overridable ဖြစ်ပါတယ်။ အဲဒီအတွက် ကျွန်တော်တို့ ကိုယ်ပိုင် Class ကနေ Finalize Method ကို Override လုပ်လို့ရပါတယ်။ ကျွန်တော်တို့ Console Application လေးနဲ့စမ်းကြည့်ရအောင်။

Public Class FileDemo
    Private fs As System.IO.FileStream

    Protected Overrides Sub Finalize()
        If fs IsNot Nothing Then
            fs.Close()
        End If
        Console.WriteLine("From Finalize Method")
    End Sub
End Class

FileDemo ဆိုတဲ့ Class ထဲမှာ External Resources တစ်ခုဖြစ်တဲ့ FileStream ကို ယူသုံးထားပါတယ်။ fs အဖြစ် ကြေငြာထားပါတယ်။ အဲဒီလို Resources မျိုးတွေဆိုရင် ကိုယ်တိုင်ပဲ Releasing လုပ်တာအကောင်းဆုံးပါ။ အဲဒီအတွက် System.Object class ထဲမှာ ရှိတဲ့ Finalize ဆိုတဲ့ method ကို Override လုပ်ပြီးပြန်ရေးလိုက်ပါတယ်။

Module Module1

    Sub Main()
        Dim t As New FileDemo
        t = Nothing
        Console.ReadLine()
    End Sub

End Module

Main ထဲမှာတော့ t ကို ခဏနေက ရေးထားတဲ့ FileDemo object အဖြစ်ကြေငြာပါတယ်။ t=Nothing လို့ရေးလို်က်တာက t ဟာ ဘာReference မှ မရှိတော့ပါဘူးလို့ GC ကို အသိပေးလိုက်တာပါ ။ GC round trip တစ်ကြိမ်အလုပ်လုပ်လို့ t ကို ဖြုတ်ချရင် t ထဲမှာရေးထားတဲ့ Finalize method ဟာလည်း သူ့အလိုလိုအလျှောက်လုပ်သွားမှာပါ။ ပြဿနာက GC round trip က ဘယ်လောက်ကြာရင် အလုပ်လုပ်မယ်ဆိုတာ ခန့်မှန်းလို့ မရတာပါပဲ။ Memory အလုံအလောက်ရှိနေသ၍ GC က ဘယ် Object ကိုမှ ဖြုတ်ချပစ်မှာ မဟုတ်ပါဘူး။ ကံကောင်းတာက GC ကို Forced ပေးပြီးတော့ အလုပ်လုပ်ခိုင်းလို့ရပါတယ်။ အဲဒါက GC ရဲ့ Collect ဆိုတဲ့ Method ပါ။ အပေါ်က ရေးထားတဲ့ Code ကို run ကြည့်ရင် From Finalize Method ကိုချက်ချင်း မြင်ရမှာ မဟုတ်ပါဘူး။

Module Module1

    Sub Main()
        Dim t As New FileDemo
        t = Nothing
        GC.Collect()
        Console.ReadLine()
    End Sub

End Module

Main ထဲမှာ GC.Collect ဆိုတဲ့ တစ်ကြောင်းဖြည့်လိုက်ရင်တော့ From Finalize Method ဆိုတဲ့စာကြောင်းကို GC.Collect ခေါ်အပြိးမှာ ချက်ချင်း မြင်ရမှာပါ။ တနည်းအားဖြင့် GC ကို Forced ပေးပြီးတော့ Memory ပေါ်က ဘာ Reference မှ မရှိတော့တဲ့ Object အားလုံးကို ဖြုတ်ချ ခိုင်းလိုက်တာပါ။ အလုပ်ဖြစ်ပေမယ့် သိပ်တော့မဟန်သေးပါဘူး။ GC.Collect လို့ ခေါ်လိုက်တာက သီးခြား Object တစ်ခုထဲကို ဖြုတ်ချ လိုက်တာတော့ မဟုတ်ပါဘူး။ အဲဒီအတွက် စက်ရဲ့ လုပ်ဆောင်မှု က နှေးကွေး သွားနိုင်ပါတယ်။ ကျွန်တော် လိုချင်တာက t ကို ဖြုတ်ချလိုက်ရင် t တစ်ခုထဲကိုပဲ လုပ်စေချင်တာပါ။ အဲဒီအတွက် နည်းလမ်းတော့ ရှိပါတယ်။ Object တွေရဲ့ Dispose ဆိုတဲ့ Method ကိုခေါ်သုံးဖို့ပါ။ Dispose ကို ခေါ်သုံးချင်ရင် ကိုယ့်ရဲ့ Class က IDisposable Interface ကို Implements လုပ်ဖို့တော့လိုအပ်ပါတယ်။

ကျွန်တော်တို့ FileDemo Class ကို အောက်ကလို ပြင်ကြည့်ရအောင်။

Public Class FileDemo
    Implements IDisposable

    Private fs As System.IO.FileStream

#Region "IDisposable Support"
    Private disposedValue As Boolean ' To detect redundant calls

    ' IDisposable
    Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If Not Me.disposedValue Then
            If disposing Then
                ' TODO: dispose managed state (managed objects).
            End If

            ' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below.
            ' TODO: set large fields to null.
        End If
        Me.disposedValue = True
    End Sub

    ' TODO: override Finalize() only if Dispose(ByVal disposing As Boolean) above has code to free unmanaged resources.
    'Protected Overrides Sub Finalize()
    '    ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
    '    Dispose(False)
    '    MyBase.Finalize()
    'End Sub

    ' This code added by Visual Basic to correctly implement the disposable pattern.
    Public Sub Dispose() Implements IDisposable.Dispose
        ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
        If fs IsNot Nothing Then
            fs.Close()
        End If
        Console.WriteLine("From Dispose Method")

        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
#End Region

End Class

Implements IDisposable လို့ရေးပြီး Enter ခေါ်လိုက်တာနဲ့ IDisposable Interface ထဲမှာ ရှိတဲ့ Method တွေ သူ့အလိုလို ပေါင်းထည့် ပေးမှာ ဖြစ်ပါတယ်။ External Resources တွေကို Releasing လုပ်ရမယ့် method က Public Sbu Dispose() Implements IDisposable.Dispose ဆိုတဲ့ Method မှာပါ။ အဲဒီမှာ fs ကို close လုပ်ထားတာတော့ အပေါ်ကအတိုင်းပါပဲ။ GC.SuppressFinalize(Me) ဆိုတာကတော့ GC ကို ဒီ Object ဖြုတ်ချတဲ့ အချိန်မှာ Finalize Method ကို သွားခေါ်စရာ မလိုတော့ဘူးလို့ ပြောလိုက်တာပါ။

Module Module1

    Sub Main()
        Dim t As New FileDemo
        t.Dispose()
        Console.ReadLine()
    End Sub

End Module

Main ထဲမှာ t.Dispose ဆိုပြီးခေါ်သုံးလို့ရသွားပါပြီ။ .Net Framework ထဲမှာ ပါတဲ့ Expensive Resources တွေကို ယူသုံးတဲ့ Object တော်တော်များများက IDisposable Interface ကို Implements လုပ်ထားပြီးသားတွေပါ။

Dispose ကိုခေါ်ရမှာပျင်းသူတွေအတွက် Using ဆိုတဲ့ Keyword ကို အသုံးပြုလို့လည်းရပါတယ်။ IDisposable Interface ကို Implements လုပ်ထားတဲ့ class တွေရဲ့ Object တွေကို Using အသုံးပြုလို့ရပါတယ်။

Module Module1

    Sub Main()
        Using t As New FileDemo
            'put some code here
        End Using
        Console.ReadLine()

    End Sub

End Module

End Using ဆိုတဲ့ တစ်ကြောင်းပြီးတာနဲ့ t.Dispose ကို သူ့အလိုအလျှောက် ခေါ်ပြီး အလုပ် လုပ်သွားမှာ ဖြစ်ပါတယ်။

Facebook comments:

Leave a comment


*