程序无法精确控制java垃圾回收的时机,但依然可以强制系统进行垃圾回收--这种强制只是通知系统进行垃圾回收, 但系统是否进行垃圾回收依然不确定。大部分时候,程序强制系统垃圾回收后总会有一些效果,强制系统垃圾回收 有如下两种方式。
1.调用System类的gc()静态方法:System.gc();
2.调用Runtime对象的gc()实例方法:Runtime.GetRuntime().gc();
public class GcTest
{
public static void main(String[] args)
{
for(int i=0;i<4;i++)
{
new GcTest();
System.gc();
}
}
public void finalize()
{
System.out.println("系统正在清理GcTest对象的资源...");
}
}
javac GcTest后也看不到任何输出
但使用下面命令可以看到清理垃圾的操作
java -verbose:gc GcTest
finalize方法
在垃圾回收机制回收某个对象所占用的内存之前,通常要求程序调用适当的方法来清理资源,在没有明确指定清理资源的情况下,java提供了默认机制清理该对象的资源,这个机制就是finalize()方法。
该方法是定义在Object类里的实例方法,方法原型为:
protected void finalize() throws Throwable
当finalize()方法返回后,对象消失,垃圾回收机制开始执行。方法原型中的throws Throwable表示它可以抛出任何类型的异常。
任何Java类都可以重写Object类的finalize()方法,在该 方法中清理该对象占用的资源,如果程序终止之前始终没有进行垃圾回收,则不会调用失去引用对象的finalize()方法清理资源。垃圾回收机制何时调用对象的finalize()方法是完全透明的,只有当程序认为需要更多的额外内存时,垃圾回收机制才会进行垃圾回收,因此,完全有可能出现这样的一种情形,某个失去引用的对象只占用了少量内存,耐用系统没有产生严重的内存需求,因此垃圾回收机制并没有试图回收该对象所占用的资源,所以该对象的finalize()方法也不会得到调用。
finalize()方法具有如下4个特点
1. 永远不要主动调用某个对象的finalize()方法,该方法应交给垃圾回收机制调用。
2.finalize()方法何时被调用,是否被调用具有不确定性,不要把finalize()方法当成一定会被执行的方法。
3.当JVM执行可恢复对象的finalize()方法时,可能使该对象或系统中其他对象重新变成可达状态。
4.当JVM执行finalize()方法时出现异常时,垃圾回收机制不会报告任何异常,程序继续执行
由于finalize()方法并不一定会被执行,因此如果想清理某个类里打开的资源,则不要放在finalize()方法中 进行清理。
public class FinalizeTest
{
private static FinalizeTest ft=null;
public void info()
{
System.out.println("测试资源清理的Finalize方法");
}
public static void main(String[] args)throws Exception
{
//创建FinalizeTest对象立即进入可恢复状态
new FinalizeTest();
//通知系统进行资源回收
System.gc();
//强制垃圾回收机制调用可恢复对象的finalize()方法
//Runtime.getRuntime().runFinalizAtion();
System.runFinalization();
ft.info();
}
public void finalize()
{
//让ft引用到试图回收的可恢复对象,即可恢复对象重新变成可达对象;
ft=this;
}
}
上面的程序中定义了一个FinalizeTest类,重写了该类的finalize()方法,在该方法中把需要清理的可恢复对象重新赋给了ft引用变量,从而让该可恢复对象重新就可达状态。
上面程序中的main()方法创建了一个FinalizeTest类的匿名对象,因为创建后没有把这个对象赋给任何引用变量,所以该对象立即进入可恢复状态。进入可恢复状态后,系统调用System.gc();通知系统进行垃圾回收,而System.runFinalization(); 强制系统立即调用可恢复对象的finalize()方法,再次调用ft对象的info方法。编辑运行上面程序 看到如下结果:
如果不执行System.gc()方法,程序并没有通知系统开始执行垃圾回收,因此系统通常不会立即 进行垃圾回收,也就不会调用 FinalizeTest对象的finalize()方法,这样FinalizeTest的ft类变量将依然保持为null,这样就导致了空指针异常。
上面程序中如果不执行 Runtime.getRuntime().runFinalization();
或System.runFinalization(); 由于JVM垃圾回收机制的不确定性,JVM往往并不立即调用可恢复对象的finalize()方法,这样FinalizeTest的ft类变量可能依然为null,可能依然会导致指针异常。