finalize()
它是Object父类里的方法,子类可以复写这个方法。
它的工作原理是这样的:当垃圾回收器确定该对象(使用new创建的对象)不再被任何其它对象引用时,垃圾回收器将在进行对该对象的内存回收之前会先调用一次该对象的finalize()方法。
假设某个对象包含一块特殊内存(native内存,非new创建的内存)时,这块特殊内存并不会被垃圾回收器释放,因此可以在该对象的finalize()方法中释放特殊内存,这样可以确保该对象相关的所有内存都会被垃圾回收器回收。这是Object类中设计finalize()方法的初衷。
但是我们并不能把这个方法当做通用的内存清理方法,原因是因为垃圾回收并不一定会发生,我们可能会发现,等到程序濒临内存用完的时候,才会发现内存得到了释放。比如andoid里的Bitmap对象,我们希望当确定bitmap对象不再使用时,应该主动的去调用recycle()方法释放内存,而不是提供一个finalize方法让垃圾回收器去执行内存回收。我们可以想象的是如果bitmap是通过finalize()去释放内存,很有可能是当程序发生了OOM时,垃圾回收器才开始执行不再使用的bitmap对象的垃圾回收,而此时已经迟了。
事实上,finalize()更为有用的是在内存优化调试时使用;另外《Java编程思想》中提供了一个“终结条件”的用法。
当对某个对象不再感兴趣——也就是说它可以被清理了。此时这个对象应该处于某种状态使它占用的内存可以被安全地释放。比如一个对象打开了一个文件,当这个对象不再被引用时,我们应该确保文件已经被关闭。因此我们可以在finalize()中添加log来发现隐藏缺陷。finalize()就是终结条件,因为对象的finalize()方法被执行,就表明该对象已经是无用的了。
示例:
public class TerminationCondition{ public static void main(String[] args){ Book novel = new Book(true); novel.checkIn(); new Book(true); for(int i = 0; i < 100; i++){ System.gc();//添加循环是因为gc()只是建议系统执行垃圾回收,但并不一定会马上执行,添加100次的循环确保对象被垃圾回收 } } } class Book{ boolean checkedOut = false; Book(boolean checkOUt){ checkedOut = checkOUt; } void checkIn(){ checkedOut = false; } protected void finalize() throws Throwable{ if(checkedOut){ System.out.println("Error: checked out"); } super.finalize(); } }
System.gc()
建议虚拟机执行垃圾回收,具体什么时候执行由虚拟机决定。程序中调用这个方法可以增大垃圾回收发生的概率。但不建议频繁执行,因为垃圾回收是耗时操作,会增加系统负担。
runFinalization()
建议执行不再被使用,即将被垃圾回收器回收的对象的finalize()方法,同gc()方法一样,只是建议虚拟机执行。实际测试中finalize()方法还是由gc发生的时候执行,并不会因为调用了runFinalization()而在gc发生之前就会执行。