zoukankan      html  css  js  c++  java
  • 【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模式替代)。

  • 相关阅读:
    MYSQL定时任务 触发器
    mybatis 学习
    SSM 记录
    环境变量配置
    servlet 拦截器 (filter)
    验证码
    jquery $.ajax({});参数详解
    maven打包忽略静态资源解决办法,dispatchServlet拦截静态资源请求的解决办法
    switch..case..
    HDU 1005 题解
  • 原文地址:https://www.cnblogs.com/hetring/p/4755516.html
Copyright © 2011-2022 走看看