1、垃圾回收
- Java的垃圾回收器只会释放由我们new出来的内存堆块,那些不是由new出来的“特殊内存”,垃圾回收器是不会管理的。
- 所谓的特殊内存指通过JNI用C/C++向系统申请的内存,这些内存如果不手动去清除就会一直占据在内存中。
- 而且,垃圾回收本身就有开销,所以虚拟机不会经常GC,只有当内存快要耗尽的时候JVM才会触发GC。
2、finalize()的定义和作用
由上,Java中的对象并不一定会被全部垃圾回收,当你不想要该对象的时候,你需要手动去处理那些“特殊内存”。
Java 允许定义这样的方法,它在对象被垃圾收集器析构(回收)之前调用,这个方法叫做 finalize( )
,它用来清除回收对象。
不建议用finalize()
方法完成“非内存资源”的清理工作,但建议用于:
① 清理本地对象(通过JNI创建的对象);
② 确保某些非内存资源(如Socket、文件等)的释放:在finalize()
方法中显式调用其他资源释放方法。
3、finalize()的隐藏问题
System.gc()
与System.runFinalization()
方法增加了finalize()
方法执行的机会,但不可盲目依赖它们- Java语言规范并不保证finalize方法会被及时地执行、而且根本不会保证它们会被执行
finalize()
方法可能会带来性能问题。因为JVM通常在单独的低优先级线程中完成finalize()
的执行- 对象再生问题:
finalize()
方法中,可将待回收对象赋值给GC Roots
可达的对象引用,从而达到对象再生的目的 finalize()
方法至多由GC执行一次(用户当然可以手动调用对象的finalize()
方法,但并不影响GC对finalize()
的行为)
finalize()
一般不用!被执行的不确定性太大。不要指望使用finalize()
来回收你的对象,它只会在系统进行GC的时候清理特殊内存,不受你的控制!
4、finalize()方法的一般格式
protected void finalize()
{
// 在这里终结代码
}
复制代码
关键字 protected
是一个限定符,它确保 finalize()
方法不会被该类以外的代码调用。
5、finalize()的执行过程(生命周期)
当对象变成(GC Roots)不可达时,GC会判断该对象是否覆盖了finalize方法,若未覆盖,则直接将其回收。否则,若对象未执行过finalize方法,将其放入F-Queue队列,由一低优先级线程执行该队列中对象的finalize方法。执行finalize方法完毕后,GC会再次判断该对象是否可达,若不可达,则进行回收,否则,对象“复活”。
具体流程参考:www.cnblogs.com/Smina/p/718…
6、实例
FinalizationDemo.java 文件代码:
public class FinalizationDemo {
public static void main(String[] args) {
Cake c1 = new Cake(1);
Cake c2 = new Cake(2);
Cake c3 = new Cake(3);
c2 = c3 = null;
System.gc(); //调用Java垃圾收集器
}
}
class Cake extends Object {
private int id;
public Cake(int id) {
this.id = id;
System.out.println("Cake Object " + id + "is created");
}
protected void finalize() throws java.lang.Throwable {
super.finalize(); //finalize的调用方法
System.out.println("Cake Object " + id + "is disposed");
}
}
复制代码
运行以上代码,输出结果如下:
$ javac FinalizationDemo.java
$ java FinalizationDemo
Cake Object 1is created
Cake Object 2is created
Cake Object 3is created
Cake Object 3is disposed
Cake Object 2is disposed
链接:https://juejin.cn/post/6844903880086536199