JVM-finalize()的简单介绍

引言:

我们知道Java是自动回收对象的,而C、C++需要手动回收对象(析构函数),但是Java的垃圾回收机制并不是万能的,垃圾回收只能回收内存,而且只能回收内存中由Java创建对象方式(堆)创建的对象所占用的内存,无法回收其它资源,比如文件操作的句柄、数据库的连接、本地对象(通过JNI创建的对象)等,为了解决这个问题Java为我们提供了finalize这个方法来完成“非内存资源”的清理工作。

finalize的生命流程

  1. 当对象不可达时(GC Roots), GC会判断对象是否覆盖了finalize(), 若未覆盖则直接将其回收. 若对象覆盖并且未执行过(手动调用的不计此列)finalize(), 将其放入F-Queue队列, 由一个低优先级线程执行该队列中对象的finalize()方法。执行finalize()完毕后, Gc会再次判断该对象是否可达, 若不可达, 则进行回收, 否则, 对象“复活”
  2. 对象可由两种状态组成, 涉及到两类状态空间: 一是终结状态空间 F = {unfinalized, finalizable, finalized}; 二是可达状态空间 R = {reachable, F(finalizer)-reachable, unreachable} unfinalized GC尚未调用对象的finalize(), 也不准备调用对象的finalize() finalizable GC尚未调用对象的finalize(), 但是会在之后的某个时间调用对象的finalize() finalized GC已经调用过对象的finalize()方法 reachable 对象被任一存活线程所引用(比如在栈中有变量引用该对象等) finalizer-reachable 对象可以被处于终结状态的对象引用或者存在引用,但并不会被任何存活的线程访问到) unreachable 对象不可通过上面两种途径可达, 也就是不可到达, 没有被任何对象引用
  3. 具体状态转换
    在这里插入图片描述

1.新建对象首先处于 [reachable, unfinalized] 状态

2.随着程序的执行, 一些引用关系会消失, 导致状态变迁, 从reachable状态变迁为 f-reachable 或 unreachable

3.若JVM检测到处于 unfinalized 状态的对象变为 f-reachable 或 unreachable, JVM会将其标记为 finalizable 状态. 若对象原处于 [unreachable, unfinalized] 状态, 则同时将其标记为 f-reachable

4.在某个时刻, JVM 取出某个 finalizable 对象, 将其标记为 finalized 并在某个线程中执行其 finalize(). 由于是在活动线程中引用了该对象, 该对象将变迁为 [reachable, finalized] 状态. 该动作将影响某些其它对象从 f-reachable 状态重新回到 reachable 状态, 这就是对象重生

5.处于 finalizable 状态的对象不能同时是 unreachable 的, 由第4点知, 将对象从 finalizable 标记为 finalized 时会由某个线程执行该对象的finalize(), 致使其变成 reachable.

6.程序员手动调用 finalize() 并不会影响到上述内容的变化, 因此JVM只会至多调用 finalize() 一次, 即使该对象 ”复活”也是如此

7.若 JVM 检测到 finalized 状态的对象变为 unreachable, 回收内存

8.若对象未覆盖 finalize(), JVM会进行优化, 直接回收对象

9.System.runFinalizersOnExit()等方法可以使对象即使处于 reachable 状态, JVM依旧对其执行 finalize()

finalize的使用场景

  1. java垃圾回收器只能回收创建在堆中的java对象,对于不是这种方式创建的对象(例如JNI本地对象),只能通过finalize()保证使用之后进行销毁、释放内存

  2. 充当保证使用之后释放资源的最后一道屏障, 比如使用数据库连接之后未断开,并且由于程序员的个人原因忘记了释放连接, 这时就只能依靠finalize()函数来释放资源

  3. 对象再生:finalize方法中,可将待回收对象赋值给GC Roots可达的对象引用,从而达到对象再生的目的

注:finalize方法至多由GC执行一次(用户当然可以手动调用对象的finalize方法,但并不影响GC对finalize的行为)

为什么尽量避免使用finalize()?

  1. Java语言规范并不保证finalize方法会被及时地执行,因为JVM通常在单独的低优先级线程中完成finalize的执行,而且根本不会保证它们会被执行。

注:程序中其他线程的优先级远远高于执行finalize()函数线程的优先级。也许等到finalize()被调用,数据库的连接池或者文件句柄早就耗尽了.或者根本就不调用finalize()方法释放资源,导致内存泄漏。

  1. 如果一种未被捕获的异常在使用finalize方法时被抛出,这个异常不会被捕获,finalize方法的终结过程也会终止,造成对象出于破坏的状态。被破坏的对象又很可能导致部分资源无法被回收, 造成浪费.
  2. finalize()和垃圾回收器的运行本身就要耗费资源, 也许会导致程序的暂时停止.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值