Java中创建引用类型对象时,都会在堆内存中分配一块区域,Java对象就保存在这块内存区域中,当这块内存区域不再被任何变量引用时,垃圾回收机制就会把这块内存区域回收。
1 垃圾回收机制的特征
垃圾回收机制只负责回收堆内存中的对象。
垃圾回收机制根据回收策略运行,程序无法精确控制。
在回收Java对象之前,会先调用该对象的finalize()方法。
2 Java对象在内存中的状态
Java对象在堆中运行时有三种状态:可达状态、可恢复状态、不可达状态。
可达状态:Java对象被创建后,如果被一个或多个变量引用,那么这个Java对象处于可达状态,即这个对象可以被访问。
可恢复状态:Java对象不再被任何变量引用就进入了可恢复状态。在这种状态下,垃圾回收机制准备回收该对象所占用的资源,在回收该对象之前,该对象的finalize()方法进行资源清理。如果在finalize()方法中重新让变量引用该对象,则该对象再次变为可达状态,否则该对象进入不可达状态。
不可达状态:Java对象不被任何变量引用,且系统在调用对象的finalize()方法后依然没有使该对象变成可达状态(该对象依然没有被变量引用),那么该对象将变成不可达状态。当Java对象处于不可达状态时,系统才会真正回收该对象所占有的资源。
3 强制垃圾回收
Java程序无法精确控制Java垃圾回收的时机,但是依然可以强制进行垃圾回收,也就是通知系统进行垃圾回收,但系统何时进行垃圾回收无法确定。不过垃圾回收机制也不会对程序的垃圾回收命令完全不理,垃圾回收机制在收到通知后会尽快进行垃圾回收。强制垃圾回收有两种方法:①调用System类的gc()静态方法。②调用Runtim对象的gc()实例方法。
public class GcDemo {
private int index;
public GcDemo(int index){
this.index = index;
}
public static void main(String[] args) {
for(int i = 0; i < 5; i++){
new GcDemo(i);
//下面两行代码的作用完全相同,强制系统进行垃圾回收
//Runtime.getRuntime().gc();
System.gc();
}
}
public void finalize(){
System.out.println("正在清理第 " + index + "个GcDemo...");
}
}
/*
程序执行的结果如下:
正在清理第 3个GcDemo...
正在清理第 0个GcDemo...
正在清理第 1个GcDemo...
正在清理第 2个GcDemo...
正在清理第 4个GcDemo...
垃圾回收并不是严格按照顺序执行的,也就是说垃圾回收不是实时的,而是根据垃圾回收机制在合适的时间触发。
*/
4 finalize()方法
在回收Java对象占用的内存之前,通常会调用适当的方法清理资源,默认情况下会调用finalize()方法来清理该对象的资源。finalize()方法在Object类中定义,在finalize()方法被调用后,垃圾回收机制开始执行。Object类的finalize()方法可以在继承类中重写(Override),用来清理继承类的资源。finalize()方法具有以下特点:
不要主动调用finalize()方法,该方法应该交给垃圾回收机制调用。
finalize()方法无法确定何时被调用,因此finalize()方法不一定会执行。
当JVM(Java虚拟机)调用finalize()方法时,可能使该对象变成可达状态。
当JVM(Java虚拟机)调用finalize()出现异常时,垃圾回收机制不会报告异常,程序继续执行。
public class FinalizeDemo {
private static FinalizeDemo fd = null;
private int index;
public FinalizeDemo(int index){
this.index = index;
}
public void print(){
System.out.println("FinalizeDemo " + index);
}
public static void main(String[] args) throws InterruptedException {
new FinalizeDemo(5);
System.gc();
//暂停2秒,以便系统进行垃圾回收。
//如果不执行①语句,那么②语句会比finalize方法先执行,这时FinalizeDemo.fd还未赋值。
Thread.sleep(2000); //①
try{
FinalizeDemo.fd.print(); //②
}catch(Exception e){
System.out.println("Error:" + new Date().getTime());
}
}
public void finalize(){
System.out.println("正在清理FinalizeDemo " + index + " :" + new Date().getTime());
fd = this;
}
}
/*
程序执行的结果如下:
正在清理FinalizeDemo 5 :1400316264637
FinalizeDemo 5
垃圾回收先执行finalize()方法,然后把对象赋给FinalizeDemo.fd。
如果把①语句注释掉,程序执行结果如下:
Error:1400316599948
正在清理FinalizeDemo 5 :1400316599948
发现②语句会比finalize()方法先执行,也就是还没有进行垃圾回收,②语句就已经执行了。
*/