Java有垃圾回收器负责回收无用对象占据的内存空间。但也有特殊情况:假定你的对象(并非使用new)获得了一块“特殊”的内存区域,由于垃圾回收器只知道释放那些经由new分配的内存,所以它不知道该如何释放该对象的这块“特殊”内存。
Java允许在类中定义一个名为finalize()方法。一旦垃圾回收期准备好释放对象占用的内存空间,首先调用其finalize()方法,并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。
在Java中,对象并非总是被垃圾回收,只要程序没有濒临内存空间用完的那一刻,对象占用的空间就中也得不到释放。如果程序执行结束,并且垃圾回收器一直没有释放创建的对象,程序结束退出后资源也会全部返回给操作系统。
这个垃圾回收策略避免了频繁垃圾回收造成的开销,Java虚拟机并未面临内存耗尽的情形,它是不会浪费时间去。
finalize()在什么时候被调用?
* 所有对象被Garbage Collection时自动调用,比如运行System.gc()的时候
* 显式的调用finalize方法
package finalize;
/**
* 程序没有濒临内存空间用完,对象占用的空间就中也得不到释放,不会调用finalize()方法,
* 程序执行结束,并且垃圾回收器一直没有释放创建的对象,程序结束退出后资源也会全部返回给操作系统。
*/
public class FinalizeTest {
public static void main(String[] args) {
for(int i = 0; i < 10; i++) {
Test t = new Test(i);
}
}
}
class Test {
public Test(int i) {
System.out.println("创建:" + this + "->" + i);
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("资源回收:" + this);
}
}
程序运行情况如下,程序内存空间充足,垃圾回收器一直没有释放创建的对象,程序结束退出后资源也会全部返回给操作系统。
创建:finalize.Test@1d44bcfa->0
创建:finalize.Test@266474c2->1
创建:finalize.Test@6f94fa3e->2
创建:finalize.Test@5e481248->3
创建:finalize.Test@66d3c617->4
创建:finalize.Test@63947c6b->5
创建:finalize.Test@2b193f2d->6
创建:finalize.Test@355da254->7
创建:finalize.Test@4dc63996->8
创建:finalize.Test@d716361->9
进程完成,退出码 0
运行System.gc(),所有对象被Garbage Collection时自动调用,程序如下:
package finalize;
/**
* 运行System.gc(),所有对象被Garbage Collection时自动调用
**/
public class FinalizeTest {
public static void main(String[] args) {
for(int i = 0; i < 10; i++) {
Test t = new Test(i);
}
System.out.println("gc()-start...");
System.gc();
System.out.println("gc()-end...");
}
}
class Test {
public Test(int i) {
System.out.println("创建:" + this + "->" + i);
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("资源回收:" + this);
}
}
程序执行情况如下所示:
创建:finalize.Test@1d44bcfa->0
创建:finalize.Test@266474c2->1
创建:finalize.Test@6f94fa3e->2
创建:finalize.Test@5e481248->3
创建:finalize.Test@66d3c617->4
创建:finalize.Test@63947c6b->5
创建:finalize.Test@2b193f2d->6
创建:finalize.Test@355da254->7
创建:finalize.Test@4dc63996->8
创建:finalize.Test@d716361->9
gc()-start...
gc()-end...
资源回收:finalize.Test@d716361
资源回收:finalize.Test@4dc63996
资源回收:finalize.Test@355da254
资源回收:finalize.Test@2b193f2d
资源回收:finalize.Test@63947c6b
资源回收:finalize.Test@66d3c617
资源回收:finalize.Test@5e481248
资源回收:finalize.Test@6f94fa3e
资源回收:finalize.Test@266474c2
资源回收:finalize.Test@1d44bcfa
进程完成,退出码 0
Java9中finalize方法已经被废弃,占有非堆资源的对象实例,类应该提供一个方法以明确释放这些资源,如果合适的话他们也应该实现AutoCloseable接口, java.lang.ref.Cleaner和java.lang.ref.PhantomReference提供更灵活和有效的方式,在对象无法再访问时释放资源。