• 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()函数虚拟机只会调用执行一次。

  • 相关阅读:
    LeetCode 811. Subdomain Visit Count (子域名访问计数)
    LeetCode 884. Uncommon Words from Two Sentences (两句话中的不常见单词)
    LeetCode 939. Minimum Area Rectangle (最小面积矩形)
    LeetCode 781. Rabbits in Forest (森林中的兔子)
    LeetCode 739. Daily Temperatures (每日温度)
    三种方式实现按钮的点击事件
    239. Sliding Window Maximum
    14.TCP的坚持定时器和保活定时器
    13.TCP的超时与重传
    12.TCP的成块数据流
  • 原文地址:https://www.cnblogs.com/naray/p/15420441.html
Copyright © 2020-2023  润新知