【C#】GC和析构函数(Finalize 方法)

析构函数:

(来自百度百科)析构函数(destructor) 与构造函数相反,当对象脱离其作用域时(例如对象所在的函数已调用完毕),系统自动执行析构函数。析构函数往往用来做“清理善后” 的工作(例如在建立对象时用new开辟了一片内存空间,应在退出前在析构函数中用delete释放)。

C#中的析构函数定义与C++ 类似,~+函数名的方法:

1     public class FinalizeClass
2     {
3         ~FinalizeClass()
4         {
5             //在这里,清理非托管资源
6         }
7     }

生成的IL代码:

 1 .class public auto ansi beforefieldinit Test.FinalizeClass
 2     extends [mscorlib]System.Object
 3 {
 4     // Methods
 5     .method family hidebysig virtual
 6         instance void Finalize () cil managed
 7     {
 8         // Method begins at RVA 0x2070
 9         // Code size 25 (0x19)
10         .maxstack 1
11
12         .try
13         {
14             IL_0000: nop
15             IL_0001: ldstr "FinalizeClass的析构函数"
16             IL_0006: call void [mscorlib]System.Console::WriteLine(string)
17             IL_000b: nop
18             IL_000c: nop
19             IL_000d: leave.s IL_0017
20         } // end .try
21         finally
22         {
23             IL_000f: ldarg.0
24             IL_0010: call instance void [mscorlib]System.Object::Finalize()
25             IL_0015: nop
26             IL_0016: endfinally
27         } // end handler
28
29         IL_0017: nop
30         IL_0018: ret
31     } // end of method FinalizeClass::Finalize
32
33     .method public hidebysig specialname rtspecialname
34         instance void .ctor () cil managed
35     {
36         // Method begins at RVA 0x20a8
37         // Code size 7 (0x7)
38         .maxstack 8
39
40         IL_0000: ldarg.0
41         IL_0001: call instance void [mscorlib]System.Object::.ctor()
42         IL_0006: ret
43     } // end of method FinalizeClass::.ctor
44
45 } // 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模式替代)。

时间: 2024-07-31 08:50:39

【C#】GC和析构函数(Finalize 方法)的相关文章

Java GC与finalize方法

1. Object类有一个finalize()方法,所有类都有这个方法. 2.JVM在回收(GC)一个对象时会调用这个对象的finalize()方法. 但是 GC是靠不住的. 3. JVM只有在内存不够用的情况下才会调用GC,调用finalize()方法.如果内存够用,对象不会被GC,finalize()方法不会被调用. 4. 因此程序中应该主动回收资源,而不是在finalize()方法中回收资源.

Java类的finalize()方法

Java的Object类提供了一个finalize()方法,签名如下: protected void finalize() throws Throwable { } 该方法在JVM进行垃圾回收时之行,所以任何类都可以Override该方法,来让自己的类的实例在被回收之前,执行一系列动作. 可以通过如下两种方式来让主动让JVM进行垃圾回收: System.gc(); Runtime.getRuntime().gc(): 但是JVM不保证立即执行gc操作. finalize()方法使用示例如下: p

Java GC机制和对象Finalize方法的一点总结

GC是什么? 为什么要有GC? GC是垃圾收集的意思(Garbage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的. 有向图垃圾回收机制 .NET的垃圾回收采用引用计数,java的垃圾回收机制采取的是有向图的方式来实现,具体的说,java程序中的每个线程对象就可以看作是一个有向图的起点,有向边从栈中的引用者指向堆中的引用对象.在这个有向图中,如果

java ----------finalize方法总结、GC执行finalize的过程

java finalize方法总结.GC执行finalize的过程 分类: Java2013-10-06 16:42 73人阅读 评论(0) 收藏 举报 finalizejavajvm 目录(?)[+] 注:本文的目的并不是鼓励使用finalize方法,而是大致理清其作用.问题以及GC执行finalize的过程. 1. finalize的作用 finalize()是Object的protected方法,子类可以覆盖该方法以实现资源清理工作,GC在回收对象之前调用该方法. finalize()与C

finalize方法与Java GC

转自http://www.threaddeath.com/ 闲逛ITEye时看到了译帝的一篇翻译博客,其中提到了关于Java类重写finalize方法后带来的诡异的GC overhead limit问题.博客的结尾非常详细的说明了这个问题产生的原理,但是始终有一个地方没有得到清晰的答案:由于finalize方法是Object类的protected方法,即无论重写与否,所有的Java类都会带有finalize方法,但为什么只有重写之后才会出现GC问题,不重写与重写的真实差别到底在哪儿? 通过思考始

【gc方法与finalize方法的区别】

finalize()和system.gc()的区别 转载 2017/12/22 finalize()是由JVM自动调用的,你可以用System.gc(),但JVM不一定会立刻执行,JVM感觉内存空间有限时,才会开始执行finalize(),至于新的对象创建个数和被收集个数不同是因为收集的对象只和JVM的垃圾收集策略有关. (1) finalize()函数是干嘛的?Java不是有Garbage Collection(以下简称gc)来负责回收内存吗? gc只能清除在堆上分配的内存(纯java语言的所

JAVA中GC时finalize()方法是不是一定会被执行?

在回答上面问题之前,我们一定要了解JVM在进行垃圾回收时的机制,首先: 一.可达性算法  要知道对象什么时候死亡,我们需要先知道JVM的GC是如何判断对象是可以回收的.JAVA是通过可达性算法来来判断对象是否存活的.这个算法的基本思路就是通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots 没有任何引用链相连时,则证明此对象是不可用的. 在JAVA语言中,可以作为GC Roots的对象包括下面几种: * 虚拟机栈(

[java]final关键字、finally关键字与finalize()方法

final关键字: final关键字通常指的是“无法改变的”,使用“无法改变”这样修饰可能出于两个原因:设计或者效率. final可以修饰变量.方法和类. 一.final变量 一个既是static又是final的域只占据一段不能改变的存储空间. 当对对象引用而不是基本类型运用final修饰时,其含义会有一点迷惑.对于基本类型,final使数值恒定不变.而用于对象引用,final使引用恒定不变.一旦引用被初始化指向一个对象,就无法再把它改为指向另一个对象.然而,对象自身却是可以修改的,java并未

System.gc()与Object.finalize()的区别

finalize()是由JVM自动调用的,你可以用System.gc(),但JVM不一定会立刻执行,JVM感觉内存空间有限时,才会开始执行finalize(),至于新的对象创建个数和被收集个数不同是因为收集的对象只和JVM的垃圾收集策略有关. 1.构造函数 要点: 构建器(Constructor)属于一种较特殊的方法类型,因为它没有返回值.这与 void返回值存在着明显的区别.对于void返回值,尽管方法本身不会自动返回什么,但仍然可以让它返回另一些东西.构建器则不同,它不仅什么也不会自 动返回