Finalize 方法和解構函式
對於應用程式所建立的大部分物件而言,您都可以依賴 .NET Framework 的記憶體回收行程,以隱含方式執行所有必要的記憶體管理工作。 但是,當您建立封裝 Unmanaged 資源的物件時,您必須在應用程式使用完這些 Unmanaged 資源後明確地釋放它們。 最常見的 Unmanaged 資源類型就是包裝作業系統資源 (例如檔案、視窗或網路連接) 的物件。 雖然記憶體回收行程能夠追蹤封裝 Unmanaged 資源之物件的存留期,但是它並沒有關於如何清除該資源的特定資訊。 對於這些類型的物件,.NET Framework 會提供 Object.Finalize 方法;當記憶體回收行程在回收該物件所使用的記憶體時,使用此一方法可讓物件適當地清除它所使用的 Unmanaged 資源。 根據預設,Finalize 方法不會執行任何動作。 如果您希望記憶體回收行程在回收物件的記憶體前先在物件上執行清除作業,您必須在您的類別中覆寫 Finalize 方法。
注意事項 |
---|
若要在 C# 中實作 Finalize 方法,您必須使用解構函式語法。在 .NET Framework 2.0 版中,Visual C++ 提供了自己的語法來實作 Finalize 方法,如 如何: 執行個體化類別和結構所述。在 .NET Framework 1.0 版和 1.1 版中,Visual C++ 和 C# 一樣,都使用解構函式語法來實作 Finalize 方法。 |
記憶體回收行程會使用稱為最終處理佇列 (Finalization Queue) 的內部結構,來記錄具有 Finalize 方法的物件。 每當您的應用程式建立具有 Finalize 方法的物件時,記憶體回收行程就會在最終處理佇列中放置一個指向該物件的項目。 最終處理佇列包含 Managed 堆積中需要先呼叫其最終處理程式碼之後,才能讓記憶體回收行程回收其記憶體的所有物件項目。
注意事項 |
---|
此處所提供的 GC.KeepAlive 方法程式碼範例,顯示積極記憶體回收如何在被回收的物件仍在執行時,即讓完成項開始執行,以及如何使用 KeepAlive 方法來防止這點。 |
Finalize 方法不應該擲回例外狀況 (Exception),因為應用程式無法處理例外狀況,而且例外狀況可能會造成應用程式結束。
實作 Finalize 方法或解構函式對於效能可能會有負面影響,因此如非必要,應該避免使用它們。 由具有 Finalize 方法之物件使用的記憶體回收至少需要進行兩次記憶體回收。 當記憶體回收行程執行回收時,它會回收無法存取之無完成項物件的記憶體。 在這一次,它不能回收無法存取的有完成項物件。 因此,它會從最終處理佇列移除這些物件的項目,並且將它們置於標記為準備最終處理之物件的清單。 這個清單中的項目會指向 Managed 堆積中已經可以呼叫其最終處理程式碼的物件。 記憶體回收行程會呼叫此一清單中物件的 Finalize 方法,然後再移除清單中的各個項目。 後續的記憶體回收將會判斷這些最終處理過的物件是否真的需要回收,因為標記為準備最終處理之物件清單中的項目已經不再指向它們了。 在這次的後續記憶體回收中,物件的記憶體才會真正地被收回。