GC和解構函式(Finalize 方法)
解構函式:
(來自百度百科)解構函式(destructor
) 與建構函式相反,當物件脫離其作用域時(例如物件所在的函式已呼叫完畢),系統自動執行解構函式。解構函式往往用來做“清理善後” 的工作(例如在建立物件時用new
開闢了一片記憶體空間,應在退出前在解構函式中用delete
釋放)。
C#
中的解構函式定義與C++
類似,~+函式名的方法:
public class FinalizeClass
{
~FinalizeClass()
{
//在這裡,清理非託管資源
}
}
生成的IL程式碼:
.class public auto ansi beforefieldinit Test.FinalizeClass
extends [mscorlib]System.Object
{
// Methods
.method family hidebysig virtual
instance void Finalize () cil managed
{
// Method begins at RVA 0x2070
// Code size 25 (0x19)
.maxstack 1
.try
{
IL_0000: nop
IL_0001: ldstr "FinalizeClass的解構函式"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: nop
IL_000d: leave.s IL_0017
} // end .try
finally
{
IL_000f: ldarg.0
IL_0010: call instance void [mscorlib]System.Object::Finalize()
IL_0015: nop
IL_0016: endfinally
} // end handler
IL_0017: nop
IL_0018: ret
} // end of method FinalizeClass::Finalize
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x20a8
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
} // end of method FinalizeClass::.ctor
} // end of class Test.FinalizeClass
實際上生成了一個Finalize
方法,內部呼叫了Base.Finalize()
方法,也就是Object
的Finalize
方法。
Finalize
方法只能由GC
呼叫,我們是不能呼叫的。下面說下GC
呼叫Finalize
的流程!
Finalization List(Queue)(終結列表)
我們new
一個物件,如果這個物件包含Finalize
方法,開闢記憶體後,指向它的指標會被存放到終結列表中(Object
物件除外)。
Freachable Queue (F-reachable終結可到達佇列)
垃圾回收開始時,被判定為垃圾(不可達)的物件如果同時存在於Finalization List
中,就會將該物件的指標從Finalization List
移除,並存入Freachable Queue
中。同時這些物件都變為可達(reachable
),不會被GC
回收,這樣就意味著這些物件提升到另一代,這裡假設為2代物件。
該佇列中的物件都是可達的,並需要執行Finalize
方法。執行Finalize
方法是由一個高優先順序的CLR
執行緒進行的,執行完畢後,會將物件的指標從Freachable Queue
中移除(當該佇列為空時,此執行緒將睡眠,在不為空時被喚醒)。
當再次進行垃圾回收時,原Freachable Queue
中的物件經過處理都變為不可達物件(2代),只有當2代記憶體不足時才會對2代物件進行垃圾回收,這些物件記憶體才會真正釋放掉。因此含有Finalize
方法的物件最少要經過兩次垃圾回收才會被真正釋放。
看圖解:
物件2、3、5、6、10包含Finalize
方法,2、5、7、9為不可達物件(GC
的目標)。
進行GC
時,由於2、5物件包含Finalize
方法,因此被放入Freachable Queue
中,變為可達物件並提升代,不進行垃圾回收。而物件7、9直接被回收。
如果原Freachable
所在代進行GC
,就會回收物件2、5的記憶體。
結論
1.含有Finalize
方法的物件最少要經過兩次垃圾回收才會被真正釋放。
2.如非必要,不建議定義Finalize
方法(用Dispose
模式替代)。
相關文章
- C++ 建構函式和解構函式C++函式
- 類的建構函式和解構函式函式
- C++入門記-建構函式和解構函式C++函式
- 構造和解構函式呼叫順序函式
- C#的IDisposable 介面和解構函式C#函式
- C++建構函式和解構函式呼叫虛擬函式時使用靜態聯編C++函式
- PHP 手冊 (類與物件) 學習筆記五:建構函式和解構函式PHP物件筆記函式
- finalize方法
- 建構函式與解構函式函式
- 預設建構函式、引數化建構函式、複製建構函式、解構函式函式
- Golang建立建構函式的方法詳解Golang函式
- 你不知道的JavaScript--Item8 函式,方法,建構函式呼叫JavaScript函式
- PostgreSQL 原始碼解讀(190)- 查詢#106(聚合函式#11 - finalize_aggregate)SQL原始碼函式
- C++知識點49——類繼承與類的構造、拷貝、operator=和解構函式C++繼承函式
- java8新特性之函式式介面、lambda表示式、介面的預設方法、方法和建構函式的引用Java函式
- PHP筆記:建構函式與解構函式PHP筆記函式
- ## 建構函式函式
- Date函式方法函式
- java方法/函式Java函式
- 關於建構函式與解構函式的分享函式
- [C#解惑] #1 在建構函式內呼叫虛方法C#函式
- 如何使用OO和函式式兩個方法實現重構? - DZone函式
- JavaScript 建構函式JavaScript函式
- del解構函式函式
- JavaScript | 函式與方法JavaScript函式
- Sanic websocket() 方法/函式Web函式
- Sanic exception() 方法/函式Exception函式
- Sanic get() 方法/函式函式
- Sanic post() 方法/函式函式
- Sanic delete()方法/函式delete函式
- Sanic listener() 方法/函式函式
- Sanic middleware() 方法/函式函式
- Sanic route() 方法/函式函式
- Sanic run() 方法/函式函式
- Sanic static() 方法/函式函式
- C++中建構函式,拷貝建構函式和賦值函式的詳解C++函式賦值
- 建構函式與普通函式的區別函式
- 【譯】JavaScript 工廠函式 vs 建構函式JavaScript函式