zoukankan      html  css  js  c++  java
  • Java 对象是否GC回收

    一、对象何时回收

      Java中,使用可达性分析算法标识对象是否回收,即使对象通过可达分析算法被标记为不可达对象,对象不一定被被回收,对象需要经过两次标记才会被回收。在第一次标记后对象会被放入“即将回收”的集合中。对象在随后的判定是否有必要执行finalize()函数后,才会被进行第二次标记,这样,对象才会被回收。

      第一次标记:

      通过可达性分析算法标记对象不可达,第一次被标记,但是,此时对象并不是一定被回收。处于缓刑阶段。

      第二次标记:

      对象第一次标记后,随后进行一次筛选,筛选条件是此对象有必要执行finalize()函数。

      1. 如果,对象没有覆盖finalize()函数,或者对象的finalize()函数已经被虚拟机调用过,那么,虚拟机将视这两种情况为“finalize()函数没有必要执行”。

      2. 如果,对象被判定有必要执行finalize()函数,那么,此对象会被增加到“F-Queue”队列中,F-Queue队列是由虚拟机自动创建的、低优化级的Finalizer线程去执行F-Queue队列中对象的finalize()函数。

      随后GC对F-Queue队列的对象进行第二标记小规模的标记。

      需要注意,这里的“执行”是指虚拟机开始运行对象的finalize()函数,但并不承诺一定等到finalzie()函数运行结束。这样设计的原因,是对象的finalize()函数如果执行耗时操作或者finalize()函数执行进入死循环,会堵塞Finalizer()线程,会导致虚拟机回收子系统崩溃。

    二、通过finalize()函数拯救被标记回收对象

      对象回收需要进行两次标记,在第二次标记后才会被回收,第一次标记是通过可达性分析算法完成,随后判定是否有必要执行finalize()函数后进行第二次标记,如果,对象有必要执行finalnze()函数,虚拟机会调用执行对象的finalize()函数。

      通过finalize()函数进行自救需要满足的条件:

      1. 对象需要覆盖finalize()函数。

      2. 对象的finalize()函数没有被虚拟机调用执行过。

      示例:

    package example;
    
    public class GCTest {
        public static GCTest TEST_HOOK = null;
    
        public void isLive() {
            System.out.println("Test, GC test object is live.");
        }
    
        @Override
        protected void finalize() throws Throwable {
            super.finalize();
            System.out.println("Test, GC test object is finalize.");
            TEST_HOOK = this;
        }
    }
    
    
    public class Main {
    
        public static void main(String[] args) {
    
            GCTest.TEST_HOOK = new GCTest();
    
            // 第一次自救
            GCTest.TEST_HOOK = null;
            System.gc();
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (GCTest.TEST_HOOK != null) {
                GCTest.TEST_HOOK.isLive();
            } else {
                System.out.println("Test, no, GCTest object is dead.");
            }
    
            GCTest.TEST_HOOK = null;
            System.gc();
            if (GCTest.TEST_HOOK != null) {
                GCTest.TEST_HOOK.isLive();
            } else {
                System.out.println("Test, no, GCTest object is died.");
            }
        }
    
    }

      结果:

    Test, GC test object is finalize.
    Test, GC test object is live.
    Test, no, GCTest object is died.
    
    Process finished with exit code 0

      第一次将变量赋值为null时,通知gc回收,会虚拟机会调用执行对象的finalize()函数,在函数中可以尝试自救,在第二次赋值null后,再次通知gc,虚拟机不会再调用对象finalize()函数,对象标记回收。对象的finalize()函数虚拟机只会调用执行一次。

  • 相关阅读:
    低压配电系统接地方式
    在MFC中添加用户自定义消息
    二维数组指针(百度)
    2009-08-12 17:19 16进制浮点数与十进制的转化 (转载)
    UCOS 中的中断处理
    转:智能卡测试操作系统技术
    转:ADO,OLEDB,ODBC,DAO的区别
    VC引用动态库
    VC引用静态库
    windows下查看静态库和动态库的导出函数
  • 原文地址:https://www.cnblogs.com/naray/p/15420441.html
Copyright © 2011-2022 走看看