java finalize方法详解

1.finalize的作用finalize()是Object的protected方法,子类可以覆盖该方法以实现资源清理工作,GC在回收对象之前调用该方法。finalize()与C++中的析构函数不是对应的。C++中的析构函数调用的时机是确定的(对象离开作用域或delete掉),但Java中的finalize的调用具有不确定性不建议用finalize方法完成“非内存资源”的清理工作…

大家好,又见面了,我是你们的朋友全栈君。

1. finalize的作用

  • finalize()是Object的protected方法,子类可以覆盖该方法以实现资源清理工作,GC在回收对象之前调用该方法。
  • finalize()与C++中的析构函数不是对应的。C++中的析构函数调用的时机是确定的(对象离开作用域或delete掉),但Java中的finalize的调用具有不确定性
  • 不建议用finalize方法完成“非内存资源”的清理工作,但建议用于:① 清理本地对象(通过JNI创建的对象);② 作为确保某些非内存资源(如Socket、文件等)释放的一个补充:在finalize方法中显式调用其他资源释放方法。

2. finalize的问题

  

  • 一些与finalize相关的方法,由于一些致命的缺陷,已经被废弃了,如System.runFinalizersOnExit()方法、Runtime.runFinalizersOnExit()方法
  • System.gc()与System.runFinalization()方法增加了finalize方法执行的机会,但不可盲目依赖它们
  • Java语言规范并不保证finalize方法会被及时地执行、而且根本不会保证它们会被执行
  • finalize方法可能会带来性能问题。因为JVM通常在单独的低优先级线程中完成finalize的执行
  • 对象再生问题:finalize方法中,可将待回收对象赋值给GC Roots可达的对象引用,从而达到对象再生的目的
  • finalize方法至多由GC执行一次(用户当然可以手动调用对象的finalize方法,但并不影响GC对finalize的行为)

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

  (1) 首先,大致描述一下finalize流程:当对象变成(GC Roots)不可达时,GC会判断该对象是否覆盖了finalize方法,若未覆盖,则直接将其回收。否则,若对象未执行过finalize方法,将其放入F-Queue队列,由一低优先级线程执行该队列中对象的finalize方法。执行finalize方法完毕后,GC会再次判断该对象是否可达,若不可达,则进行回收,否则,对象“复活”。

(2) 具体的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:对象不可通过上面两种途径可达
状态变迁图:
java finalize方法详解

 

变迁说明:

  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)。
  4. 在某个时刻,JVM取出某个finalizable对象,将其标记为finalized并在某个线程中执行其finalize方法。由于是在活动线程中引用了该对象,该对象将变迁到(reachable, finalized)状态(K或J)。该动作将影响某些其他对象从f-reachable状态重新回到reachable状态(L, M, N)
  5. 处于finalizable状态的对象不能同时是unreahable的,由第4点可知,将对象finalizable对象标记为finalized时会由某个线程执行该对象的finalize方法,致使其变成reachable。这也是图中只有八个状态点的原因
  6. 程序员手动调用finalize方法并不会影响到上述内部标记的变化,因此JVM只会至多调用finalize一次,即使该对象“复活”也是如此。程序员手动调用多少次不影响JVM的行为
  7. 若JVM检测到finalized状态的对象变成unreachable,回收其内存(I)
  8. 若对象并未覆盖finalize方法,JVM会进行优化,直接回收对象(O)
  9. 注:System.runFinalizersOnExit()等方法可以使对象即使处于reachable状态,JVM仍对其执行finalize方法

4. 一些代码示例

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;  
    }  
}  

  

转载于:https://www.cnblogs.com/llljjc/p/10925566.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/125369.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 测试用例编写八大要素

    测试用例编写八大要素编写测试用例的8大要素有:用例编号,所属模块,测试标题,重要级别,前置条件,测试输入,操作步骤,预期结果。以及编写测试用例时的注意事项。一、用例编号由字符和数字组合成的字符串,测试用例编号应该具有唯一性、易识别。如系统测试的用例编号格式为:产品编号-ST-系统测试项名-系统测试子项名-xxx。(备注:每个公司对于用例书写的规则不尽相同,具体细则还需要参考公司配置命名规范)二…

    2022年6月28日
    22
  • vb中如何连接mysql_vb怎么连接数据库「建议收藏」

    vb怎么连接数据库[编辑]概述我们对数据库进行操作时,一方面要使用户可以在程序界面上对需要的数据进行访问;另一方面可以对数据库中的数据进行各种操作,最终的操作结果还要反馈给用户。一、Data控件1.设置数据控件的属性2.将Data控件连到一个特定的数据库和其中的一个表上3.在VB中建立一个标准的工程4.在窗体中添加控件(Data1就是一个Data控件)5.改变控件的一些属性6.对Data控件进行设…

    2022年4月16日
    56
  • osip状态机分析「建议收藏」

    osip状态机分析「建议收藏」OSIP的核心是系统状态机,在不同情况下,系统处于不同的状态,在某一状态下当系统发生某一个动作后(如接受或者发送了消息),状态机做相应的跳转。的状态机在不同的状态下,对某一动作的响应也是不一样的。由于SIP的复杂性,为了降低代码实现难度,也为了能够保证代码的模块化,Osip把整个SIP的实现分成了四个状态机,分别是:      (1)ICT(带invit事件的out处理)

    2022年6月15日
    23
  • 什么是宽字节注入_innodb_buffer_pool_size

    什么是宽字节注入_innodb_buffer_pool_size宽字节注入产生的原理宽字节注⼊源于程序员设置MySQL连接时错误配置为:setcharacter_set_client=gbk,这样配置会引发编码转换从⽽导致的注⼊漏洞。具体原理如下:1,正常情况下当GPC开启或使⽤addslashes函数过滤GET或POST提交的参数时,⿊客使⽤的单引号’就会被转义为:’;2,但如果存在宽字节注⼊,我们输⼊%df%27时⾸先经过上⾯提到的单引号转义变成了%…

    2022年10月14日
    0
  • 常用乘法公式_初中乘法公式有哪些

    常用乘法公式_初中乘法公式有哪些1、平方差公式$$a^2b^2=(a+b)(ab)$$2、完全平方公式$$(a±b)^2=a^2±2ab+b^2$$3、完全立方公式$$(a±b)^3=a^

    2022年8月4日
    3
  • django 自定义user_tb程序化交易模型源码

    django 自定义user_tb程序化交易模型源码前言Django为我们提供了内置的User模型,不需要我们再额外定义用户模型,建立用户体系了。它的完整的路径是在django.contrib.auth.models.User。User模型源码分析

    2022年7月29日
    7

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号