GC的特殊情况与finalize()的“假定”原理
GC负责回收无用对象占据的内存资源。但也有特殊情况:假定你的对象(并非使用new)获得了一块“特殊”的内存区域,由于垃圾回收器只知道释放那些经由new分配的内存,所以它不知道该如何释放该对象的这块“特殊”内存。为了应对这种情况,Java允许在类中定义一个名为finalize()的方法。它的工作原理“假定”是这样的:一旦GC准备好释放对象占用的存储空间,将首先调用其finalize()方法,并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。finalize()的作用?
1.释放“特殊”内存
gc只能清除在堆上分配的内存,而不能清除在栈上分配的内存,当使用JNI技术令Java调用C或C++代码时,可能会在栈上分配内存(例如Java调用C程序,C使用malloc分配内存),这时要想释放存储空间,gc起不到任何作用,除非调用C的free函数,否则存储空间将得不到释放,从而造成内存泄露,所以需要在finalize()中用本地方法调用它。
2.验证终结条件(可能的使用方式)
例如,要是对象代表了一个打开的文件,在对象被回收前程序员应该关闭这个文件。只要对象中存在没有被适当清理的部分,程序就存在很隐晦的缺陷,finalize()可以用来最终发现这种情况--虽然它并不总会被调用。
public class Book {
boolean checkedOut = false;
Book(boolean checkOut){
checkedOut = checkOut;
}
void checkIn(){
checkedOut = false;
}
protected void finalize(){
if(checkedOut)
System.out.println("finalize() called!");
}
public static void main(String[] args) {
for(int i = 0; i < 100; i++){
Book novel = new Book(true);
novel.checkIn();
}
new Book(true);
System.gc();
}
}
/*验证结果是大多数情况下finalize()会被调用*/
Output: finalize() called!<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span>
finalize()何时被调用?
1.所有对象被GC时自动调用
2.程序退出时为每一个对象调用finalize()方法
3.在程序中调用System.gc()(但也只是建议JVM执行而不一定马上执行),直到1
此外,当某个对象被系统收集为无用信息的时候,finalize()将被自动调用,但是jvm不保证finalize()一定被调用,也就是说,finalize()的调用是不确定的,这也就是为什么sun不提倡使用finalize()的原因.。
System.gc()的作用?
当显示地调用System.gc()时,System.gc()会建议JVM进行GC,但决定权还是留在JVM手里,由它决定是否回收垃圾。
public class Test {
protected void finalize(){
System.out.println("finalize() called!");
}
public static void main(String[] args) {
new Test();
System.gc();
}
}
/*验证结果是大多数情况下finalize()会被调用*/
Output: finalize() called!