小喵寫這篇是源自於小喵上一篇文章【物件Object的New,Dispose與Connection的Open,Close概念分享】,小喵最後描述【當物件Dispose的時候,並沒有把該段記憶體清空,只是標註,這段空間不再使用,直到GC啟動把他清空才算真正的清空。】。但是小喵看一些網路文章時,有些卻提到當呼叫Dispose的時候,記憶體立即釋放。因此小喵就做這個測試來看看到底是怎麼回事。
緣起:
小喵寫這篇是源自於小喵上一篇文章【物件Object的New,Dispose與Connection的Open,Close概念分享】,小喵最後描述【當物件Dispose的時候,並沒有把該段記憶體清空,只是標註,這段空間不再使用,直到GC啟動把他清空才算真正的清空。】。但是小喵看一些網路文章時,有些卻提到當呼叫Dispose的時候,記憶體立即釋放。因此小喵就做這個測試來看看到底是怎麼回事。
測試計畫:
於是小喵寫了個小小的Console程式,然後裡面使用一個小類別,該類別在New的時候,讀取一個很大的文字檔,並且把文字檔的內容放到一個變數中。讓這個類別使用大量的記憶體。接著呼叫Dispose將物件釋放,最後呼叫GC.Collect強迫做資源回收。在這個過程中,小喵使用系統中的工具【效能】來監視這個程式的記憶體使用狀況,藉此來觀察Dispose時,是否立即釋放記憶體。
程式準備:
首先先寫個Console的程式,在專案中開啟一個【主控台應用程式 】,然後在專案中新增一個類別,這個類別因為需要有Dispose的功能,因此小喵【Implements System.IDisposable】的介面,讓這個類別有可以進行Dispose,接著安排屬性,撰寫New時的讀取文字檔內容。相關程式如下:
Class:myTestObj
Imports System.IO
Public Class myTestObj
Implements System.IDisposable
Private m_TestStr As String
Public Property TestStr() As String
Get
Return m_TestStr
End Get
Set(ByVal value As String)
m_TestStr = value
End Set
End Property
Public Sub New()
End Sub
Public Sub New(ByVal myFileName As String)
m_TestStr = My.Computer.FileSystem.ReadAllText(myFileName)
End Sub
Private disposedValue As Boolean = False ' 偵測多餘的呼叫
' IDisposable
Protected Overridable Sub Dispose(ByVal disposing As Boolean)
If Not Me.disposedValue Then
If disposing Then
' TODO: 釋放其他狀態 (Managed 物件)。
m_TestStr = ""
End If
' TODO: 釋放您自己的狀態 (Unmanaged 物件)
' TODO: 將大型欄位設定為 null。
End If
Me.disposedValue = True
End Sub
#Region " IDisposable Support "
' 由 Visual Basic 新增此程式碼以正確實作可處置的模式。
Public Sub Dispose() Implements IDisposable.Dispose
' 請勿變更此程式碼。在以上的 Dispose 置入清除程式碼 (ByVal 視為布林值處置)。
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
#End Region
End Class
接著在Console程式中,就使用該類別,之後Dispose接著呼叫GC.Collect做資源回收,程式如下:
Module Module1
Sub Main()
Dim oTest As myTestObj
Try
oTest = New myTestObj("xx.txt")
Catch ex As Exception
Finally
oTest.Dispose()
GC.Collect()
End Try
End Sub
End Module
剩下就是準備一個夠大的文字檔,讓記憶體的使用比較明顯,小喵準備一個23MB的文字檔
接著就是測試的開始囉
先開啟【控制台】中的【系統管理工具】找到【可靠性和效能監視器】
然後按下F11讓程式啟動,接著在校能監視器中,新增一個監視,選擇【Process】,接著選擇【PageFileBytes】,並選擇我們的Process【ConsoleApplication1.vshost】藉此觀察記憶體的使用狀況。
測試結果:
測試過程小喵錄製下來,請參考以下的錄影過程
http://vip2.blueshop.com.tw/topcat/DEMO/Dispose_GC/Dispose_GC.html
相關的程式碼,您可以到按此下載
http://vip2.blueshop.com.tw/topcat/DEMO/Dispose_GC/ConsoleApplication1.rar
從錄影的過程觀察到,當系統進行完Dispose之後,事實上記憶體並沒有立即釋放,而是直到呼叫了GC.collect之後才真正的釋放。
特別聲明:
GC.Collect方法是強制作業系統做資源回收的動作,不過請您在寫程式的時候不要這麼做,因為GC.Collect作用的區域並不只有你的程式部分,而是整個系統。並且這個動作是強制性的。再進行這個過程中,由於需要對全部的東西強制資源回收,所以該主機上其他的動作會等他做完之後再開始。其實這個動作.NET Framework自己會依照系統的狀況自己處理。手動處理反而可能造成系統的負擔(想想馬路上隨時有救護車跑來跑去,頻率很高,大家都要停下來等他過)。因此寫程式時,只要使用Dispose讓系統標注這個記憶體可以被使用即可。有需要的時候讓系統自然啟動去清除。不要手動清除他。
以下是簽名:
- 歡迎轉貼本站的文章,不過請在貼文主旨上加上【轉貼】,並在文章中附上本篇的超連結與站名【topcat姍舞之間的極度凝聚】,感恩大家的配合。
- 小喵大部分的文章會以小喵熟悉的語言VB.NET撰寫,如果您需要C#的Code,也許您可以試著用線上的工具進行轉換,這裡提供幾個參考
Microsoft MVP Visual Studio and Development Technologies (2005~2019/6) | topcat Blog:http://www.dotblogs.com.tw/topcat |