析构函数:

(来自百度百科)析构函数(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模式替代)。

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

  1. Java类的finalize()方法

    Java的Object类提供了一个finalize()方法,签名如下: protected void finalize() throws Throwable { } 该方法在JVM进行垃圾回收时之行, ...

  2. java的finalize()方法与C++的析构函数

    ---<java编程思想> 读书笔记 --- 2017/3/15 读<java编程思想>读到初始化与清理一章,文中提及java的finalize()方法,联想到了C++的析构函 ...

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

    注:本文的目的并不是鼓励使用finalize方法,而是大致理清其作用.问题以及GC执行finalize的过程. 1. finalize的作用 finalize()是Object的protected方法 ...

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

    在回答上面问题之前,我们一定要了解JVM在进行垃圾回收时的机制,首先: 一.可达性算法  要知道对象什么时候死亡,我们需要先知道JVM的GC是如何判断对象是可以回收的.JAVA是通过可达性算法来来判断 ...

  5. finalize()方法什么时候被调用?析构函数(finalization)的目的是什么?

    链接:https://www.nowcoder.com/questionTerminal/d8eab06913084e42b515633604eef7cd?pos=28&mutiTagIds= ...

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

    finalize()是由JVM自动调用的,你可以用System.gc(),但JVM不一定会立刻执行,JVM感觉内存空间有限时,才会开始执行finalize(),至于新的对象创建个数和被收集个数不同是因 ...

  7. Java finalize方法使用

    <JAVA编程思想>: Java提供finalize()方法,垃圾回收器准备释放内存的时候,会先调用finalize(). (1).对象不一定会被回收. (2).垃圾回收不是析构函数. ( ...

  8. java的finalize方法使用

    1. finalize的作用 finalize()是Object的protected方法,子类可以覆盖该方法以实现资源清理工作,GC在回收对象之前调用该方法. finalize()与C++中的析构函数 ...

  9. finalize方法的使用

    finalize()是在java.lang.Object里定义的,也就是说每一个对象都有这么个方法.这个方法在gc启动,该对象被回收的时候被调用.其实gc可以回收大部分的对象(凡是new出来的对象,g ...

随机推荐

  1. Linux小白基础命令操作

    [root@localhost ~]]# [当前登录系统的用户@主机名称 当前所在的目录]# #表示为管理员登录 $ 表示为普通用户登录 切换用户su 用户名     切换后所在目录不变  ,#变成$ ...

  2. 家庭账本开发day07

    返回数据问题解决,需要按照规定的json数据进行返回. 利用jsonobejact或者GSON工具将对象ArrayList转化为json 格式.然后response.getWriter().write ...

  3. stream之map的用法

    一.Stream管道流map的基础用法 最简单的需求:将集合中的每一个字符串,全部转换成大写! List<String> alpha = Arrays.asList("Monke ...

  4. java并发编程基础——线程相关的类

    线程相关类 java还为线程安全提供了一些工具类. 一.ThreadLocal类(Thread Local Variable) ThreadLocal类,是线程局部变量的意思.功用非常简单,就是为每一 ...

  5. python -- 面向对象编程(属性、方法)

    一.属性 对象的属性(attribute)也叫做数据成员(data member). 如果想指向某个对象的属性,可以使用格式: object.attribute 属性又分为:私有属性和公有属性. 私有 ...

  6. ThinkPHP中使用Verify类生产验证码不显示的原因

    今天在做网站部署的时候,发现登录页面的验证码显示不出来了,而且不报任何错误. 直接通过url访问该操作也不能显示. 后来在网上查找了一些解决方法. 在调用$verify = new \Think\Ve ...

  7. Java实战:教你如何进行数据库分库分表

    摘要:本文通过实际案例,说明如何按日期来对订单数据进行水平分库和分表,实现数据的分布式查询和操作. 本文分享自华为云社区<数据库分库分表Java实战经验总结 丨[绽放吧!数据库]>,作者: ...

  8. CF1214E Petya and Construction Set题解

    原来这就叫构造题,了 这道题的做法,我自己诌了一个形象的名字--"挂葡萄"法( 首先,"搭葡萄架":考虑到每个距离 \(d_i\) 只与 \(2i-1,2i\) ...

  9. 使用hsdis-amd64.dll打印java的汇编文件

    文件放在D:\DeveSOFTWARE\jdk1.8.0_45\jre\bin目录下 hsdis-amd64.dll 下载路径:https://github.com/atzhangsan/file_l ...

  10. js学习笔记之日期倒计时(天,时,分,秒)

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...