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才回收掉
https://www.cnblogs.com/QG-whz/p/6557333.html
java的finalize()方法与C++的析构函数
一旦C++的对象要被回收了,在回收该对象之前对象的析构函数将被调用,然后释放对象占用的内存;而java中
一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用其finalize()方法, 并且在下一次垃圾回收动作发生时,才会真正的回收对象占用的内存(《java 编程思想》)
可见在java中,调用GC不等于真正地回收内存资源,而且在垃圾回收中对象存在状态的变化。