finalize方法是什么

finalize方法是Object的protected方法,Object的子类们可以覆盖该方法以实现资源清理工作,GC在首次回收对象之前调用该方法。

finalize方法与C++的析构函数的区别

finalize方法与C++中的析构函数不是对应的,C++中的析构函数调用的时机是确定的(对象离开作用域或delete掉),但Java中的finalize的调用具有不确定性,不建议用finalize方法完成“非内存资源”的清理工作。

finalize方法合适清理的对象

  1. 清理本地对象(通过JNI创建的对象);
  2. 作为确保某些非内存资源(如Socket、文件等)释放的一个补充,在finalize方法中显式调用其他资源释放方法。

可以触发finalize执行的方法

在Java中含有一些一些与finalize相关的方法,由于一些致命的缺陷,已经被废弃了,如System.runFinalizersOnExit() 方法、Runtime.runFinalizersOnExit() 方法、

System.gc()System.runFinalization() 方法。

他们增加了finalize方法执行的机会,但不可盲目依赖它们Java语言规范并不保证finalize方法会被及时地执行、而且根本不会保证它们会被执行finalize方法可能会带来性能问题。

因为JVM通常在单独的低优先级线程中完成finalize的执行。

finalize实现对象再生问题

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

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

finalize的执行过程(生命周期)

  1. 大致描述一下finalize的运行流程:当对象变成(GC Roots)不可达时,GC会判断该对象是否覆盖了finalize方法,若未覆盖,则直接将其回收。

  2. 若对象未执行过finalize方法,将其放入F-Queue队列,由低优先级线程执行该队列中对象的finalize方法。执行finalize方法完毕后,GC会再次判断该对象是否可达,若不可达,则进行回收,否则,对象“复活”。

对象对于finalize方法的两种状态

对象可由两种状态,涉及到两类状态空间,一是终结状态空间 F = {unfinalized, finalizable, finalized};二是可达状态空间 R = {reachable, finalizer-reachable, unreachable}。

终结状态空间

各状态含义如下:

  • unfinalized: 新建对象会先进入此状态,GC并未准备执行其finalize方法,因为该对象是可达的。

  • finalizable: 表示GC可对该对象执行finalize方法,GC已检测到该对象不可达。正如前面所述,GC通过F-Queue队列和一专用线程完成finalize的执行。

对应的流程图如下所示:

可达状态空间

各状态含义如下:

  • finalized: 表示GC已经对该对象执行过finalize方法
  • reachable: 表示GC Roots引用可达
  • finalizer-reachable(f-reachable):表示不是reachable,但可通过某个finalizable对象可达
  • unreachable:对象不可通过上面两种途径可达

状态变迁图:

变迁说明:

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

  2. 随着程序的运行,一些引用关系会消失,导致状态变迁,从reachable状态变迁到f-reachable(B, C, D) 或 unreachable(E, F)状态

  3. JVM检测到处于unfinalized状态的对象变成f-reachable或unreachable。

    • JVM会将其标记为finalizable状态(G,H)。若对象原处于[unreachable, unfinalized]状态,则同时将其标记为f-reachable(H)。

在某个时刻,JVM取出某个finalizable对象,将其标记为finalized并在某个线程中执行其finalize方法。

  1. 由于是在活动线程中引用了该对象,该对象将变迁到(reachable, finalized)状态(K或J)。该动作将影响某些其他对象从f-reachable状态重新回到reachable状态(L, M, N)处于finalizable状态的对象不能同时是unreahable的。

  2. 将对象finalizable对象标记为finalized时会由某个线程执行该对象的finalize方法,致使其变成reachable。

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

代码示例

对象复活

public class GC {
public static GC SAVE_HOOK = null;
public static void main(String[] args) throws InterruptedException {
SAVE_HOOK = new GC();
SAVE_HOOK = null;
System.gc();
Thread.sleep(500);
if (null != SAVE_HOOK) { //此时对象应该处于(reachable, finalized)状态
System.out.println("Yes , I am still alive");
} else {
System.out.println("No , I am dead");
}
SAVE_HOOK = null;
System.gc();
Thread.sleep(500);
if (null != SAVE_HOOK) {
System.out.println("Yes , I am still alive");
} else {
System.out.println("No , I am dead");
}
} @Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("execute method finalize()");
SAVE_HOOK = this;
}
}

覆盖finalize方法以确保资源释放

作为一个补充操作,以防用户忘记“关闭“资源,JDK中FileInputStream、FileOutputStream、Connection类均用了此”技术“,下面代码摘自FileInputStream类

/**
* Ensures that the <code>close</code> method of this file input stream is
* called when there are no more references to it.
*
* @exception IOException if an I/O error occurs.
* @see java.io.FileInputStream#close()
*/
protected void finalize() throws IOException {
if ((fd != null) && (fd != FileDescriptor.in)) {
/* if fd is shared, the references in FileDescriptor
* will ensure that finalizer is only called when
* safe to do so. All references using the fd have
* become unreachable. We can call close()
*/
close();
}
}

注意:我们自己手动调用finalize方法并不会影响到上述内部标记的变化,因此JVM只会至多调用finalize一次,即使该对象“复活”也是如此。我们手动调用多少次不影响JVM的行为

若JVM检测到finalized状态的对象变成unreachable,回收其内存(I),若对象并未覆盖finalize方法,JVM会进行优化,直接回收对象(O)

【Java技术专题】「原理专题」深入分析Java中finalize方法的作用和底层原理的更多相关文章

  1. Java中finalize()方法的作用

    finalize方法是Object提供的的实例方法,使用规则如下: 当对象不再被任何对象引用时,GC会调用该对象的finalize()方法 finalize()是Object的方法,子类可以覆盖这个方 ...

  2. paip.编程语言方法重载实现的原理及python,php,js中实现方法重载

    paip.编程语言方法重载实现的原理及python,php,js中实现方法重载 有些语言,在方法的重载上,形式上不支持函数重载,但可以通过模拟实现.. 主要原理:根据参数个数进行重载,或者使用默认值 ...

  3. 自己(转)JAVA中toString方法的作用

    JAVA中toString方法的作用 因为它是Object里面已经有了的方法,而所有类都是继承Object,所以“所有对象都有这个方法”. 它通常只是为了方便输出,比如System.out.print ...

  4. Servlet工作原理解析 《深入分析java web 技术内幕》第九章

    参考关于servblet的相关文章 侧重概况:https://blog.csdn.net/levycc/article/details/50728921 ibm的相关:https://www.ibm. ...

  5. Java已五年1—二本物理到前端实习生到Java程序员「回忆贴」

    关键词:郑州 二本 物理专业 先前端实习生 后Java程序员 更多文章收录在码云仓库:https://gitee.com/bingqilinpeishenme/Java-Tutorials 前言 没有 ...

  6. 巧用 .NET 中的「合并运算符」获得 URL 中的参数

    获取 URL 中的 GET 参数,无论用什么语言开发网站,几乎是必须会用到的代码.但获取 URL 参数经常需要注意一点就是要先判断是否有这个参数存在,如果存在则取出,如果不存在则用另一个值.这个运算称 ...

  7. java回收finalize方法的作用(编程思想)

    清理:终结处理和垃圾回收 java有垃圾回收期负责回收无用对象占据的内存资源.但也有这种情况:假定你的对象(并非使用new)获得了一块“特殊”的内存区域,由于垃圾回收期只知道释放那些由new分配的内存 ...

  8. JAVA基础篇 之 finalize()方法的作用

    ​ 我们知道java有垃圾回收器负责回收无用对象占据的内存资源,但也有特殊情况:假设你的对象(并非使用new)获得了一块特殊的内存区域,由于垃圾回收器只知道回收那些经由new分配的内存,所以它不知道如 ...

  9. Java中finalize方法用途何在?

    package thinking.in.java.demo; /* * finalize的用途何在? * *本例的终止条件是L所有的Book对象在被当做垃圾回收前都应该被签入.但是在main方法中 * ...

  10. JAVA中toString方法的作用

    因为它是Object里面已经有了的方法,而所有类都是继承Object,所以“所有对象都有这个方法”. 它通常只是为了方便输出,比如System.out.println(xx),括号里面的“xx”如果不 ...

随机推荐

  1. Libgdx游戏开发(2)——接水滴游戏实现

    原文:Libgdx游戏开发(2)--接水滴游戏实现 - Stars-One的杂货小窝 本文使用Kotlin语言开发 通过本文的学习可以初步了解以下基础知识的使用: Basic file access ...

  2. 云原生时代的DevOps平台设计之道

    开发人员与运维人员是 IT 领域很重要的两大人群,他们都会参与到各种业务系统的建设过程中去.DevOps 是近年间火爆起来的一种新理念,这种理念被很多人错误的解读为"由开发人员(Dev)学习 ...

  3. 【做题笔记】CSP-S 往年试题

    题单 本文章正在持续更新-- [2021] 廊桥分配 题目 题面描述 所有飞机分为两类--国内区和国际区,两区廊桥数量互不干扰.每架飞机遵循"先到先得"的原则,优先选择编号最小的廊 ...

  4. Jedis测试redis。(redis在linux虚拟机中)

    文章目录 1.确保虚拟机开启.并且连接到redis 2.建立一个maven工程 3.在pom中加入jedis的依赖 4.编写测试用例 5.测试结果 1.确保虚拟机开启.并且连接到redis 2.建立一 ...

  5. 累加和为 K 的子数组问题

    累加和为 K 的子数组问题 作者:Grey 原文地址: 博客园:累加和为 K 的子数组问题 CSDN:累加和为 K 的子数组问题 题目说明 数组全为正数,且每个数各不相同,求累加和为K的子数组组合有哪 ...

  6. Python全栈工程师之从网页搭建入门到Flask全栈项目实战(3) - 入门Flask微框架

    1.安装Flask 方式一:使用pip命令安装 pip install flask 方式二:源码安装 python setup.py install 验证 第一个Flask程序 程序解释 参数__na ...

  7. nordic——nrf52系列SWD设置回读保护

    在开发时可能需要回读保护功能,在产品出厂后这个功能可以让你的代码更加安全,无法用SEGGER或者其余方式读取你的代码HEX文件,也就是禁用SWD下载接口.但是SWD锁住了,还想使用(从新下载代码)也是 ...

  8. Mybatis 报错Mapper method 'xxx' has an unsupported return type

    报错原因: 出现这种错误,说明sql语句执行成功,只是返回类型出了问题. 解决方法: insert.delete.update操作默认返回一个int类型的整数,将增删改的接口改成int或者void即可 ...

  9. 使用 Cravatar 解决 Gravatar 头像无法访问的问题

    Gravatar全球通用头像服务 1.基本介绍 Gravatar,即全球公认的头像,是一项免费的头像服务,适用于网站所有者,开发人员以及任何想要轻松且经过验证的在线身份的人.它被内置在每个WordPr ...

  10. k8s 中的 ingress 使用细节

    k8s中的ingress 什么是ingress Ingress 如何使用 ingress 使用细节 参考 k8s中的ingress 什么是ingress k8s 中使用 Service 为相同业务的 ...