java finalize及实践

https://www.cnblogs.com/Smina/p/7189427.html 

 

1. finalize的作用

 

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

2. finalize的问题

  • 一些与finalize相关的方法,由于一些致命的缺陷,已经被废弃了,如System.runFinalizersOnExit()方法、Runtime.runFinalizersOnExit()方法
  • System.gc()与System.runFinalization()方法增加了finalize方法执行的机会,但不可盲目依赖它们
  • Java语言规范并不保证finalize方法会被及时地执行、而且根本不会保证它们会被执行 由于gc是守护线程,可能不会调用finalize
  • finalize方法可能会带来性能问题。因为JVM通常在单独的低优先级线程中完成finalize的执行(可能达400倍)
  • 超类中的finalize()方法需要显示的调用,super.finalize(),会忘记
  • 任何有finalize()方法抛出的异常都会被GC线程忽略(优先级低)而且不会被进一步传播,事实上也不会在日志文件上记录下来http://blog.csdn.net/maoyeqiu/article/details/49562093
  • 对象再生问题:finalize方法中,可将待回收对象赋值给GC Roots可达的对象引用,从而达到对象再生的目的
  • finalize方法至多由GC执行一次(用户当然可以手动调用对象的finalize方法,但并不影响GC对finalize的行为)
  • 造成gc卡顿

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

 

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

 证明:

public class TestGcFinalize {

    public static void main(String []f) throws InterruptedException {

        NoFinalize noFinalize = new NoFinalize();
        WithFinalize withFinalize = new WithFinalize();
        noFinalize = null;
        withFinalize = null;
        System.gc();
        System.out.println("1d");
        Thread.sleep(20000);  // jmap -dump:format=b,file=dump1.dump <pid> nolive
        System.out.println("s2");
        System.gc();
        System.out.println("2d");
        Thread.sleep(20000);  // jmap -dump:format=b,file=dump1.dump <pid> nolive
        System.out.println("d");
    }

    private static class NoFinalize {

    }

    private static class WithFinalize {

        @Override
        public void finalize() {
            System.out.println("finalize");
        }
    }
}

      NoFinalize    WithFinalize

第一次gc  直接回收    调用finalize,下次回收

第二次gc       /        回收

 可以看到第一次gc,虽然调用了WithFinalize的finazlize方法,但没有直接回收掉,直到第二次gc才回收掉

finalizedump.zip

https://www.cnblogs.com/QG-whz/p/6557333.html

java的finalize()方法与C++的析构函数

 一旦C++的对象要被回收了,在回收该对象之前对象的析构函数将被调用,然后释放对象占用的内存;而java中

一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用其finalize()方法, 并且在下一次垃圾回收动作发生时,才会真正的回收对象占用的内存(《java 编程思想》)

可见在java中,调用GC不等于真正地回收内存资源,而且在垃圾回收中对象存在状态的变化。


原文地址:https://www.cnblogs.com/silyvin/p/9106669.html