Thinking in java自讀筆記:finalize()方法的作用
關於finalize與垃圾回收的兩個注意點:
(一)finalize是在垃圾回收之前被呼叫,但不一定會被呼叫
(二)垃圾回收只與記憶體有關
一旦垃圾收集器準備好釋放物件佔用的儲存空間,它首先呼叫finalize(),而且只有在下一次垃圾收集過程中,才會真正回收物件的記憶體。但值得注意的一點是,並不是所有的廢棄物件都會被垃圾收集器收集,如果不是記憶體即將耗盡,垃圾收集器不會去自動釋放記憶體,因為釋放記憶體也需要佔用資源,當然可以強行呼叫GC。
測試程式碼如下:
import java.util.LinkedList;
public class Test {
public static void main(String[] args)
{
LinkedList<Student> ls=new LinkedList<Student>();
for(int i=0;i<10;i++)
{
new Student(i);
}
System.gc();
// System.runFinalization();
}
}
class Student
{
int i;
Student(int num)
{
this .i=num;
}
@Override
protected void finalize() {
System.out.println("編號i="+i+"被清除");
}
}
在測試程式碼中,用一個迴圈生成了指定數量的“廢棄”Student物件,強制呼叫GC觀察輸出結果。如果指定的數量比較大,GC會自動呼叫,輸出的結果如下:
在輸出中我們可以看到,10個”廢棄”物件只有6個被清除掉,因此finalize並不是一定會被執行的(廢棄物件不一定會被釋放掉),如果將// System.runFinalization()註釋取消掉,輸出結果如下:
我們可以看到所有”廢棄”物件全部被清除掉,但在這裡的所有廢棄物件是收集到的所有物件
import java.util.LinkedList;
public class Test {
public static void main(String[] args)
{
LinkedList<Student> ls=new LinkedList<Student>();
for(int i=0;i<1000000;i++)
{
new Student(i);
}
System.gc();
System.runFinalization();
System.out.println(Student.num);
}
}
class Student
{
static int num=0;
int i;
Student(int num)
{
this.i=num;
}
@Override
protected void finalize() {
System.out.println("編號i="+i+"被清除");
num++;
}
}
輸出如下:
根據結果,可以明顯的看到1000000個物件只釋放掉了999992個物件,因此我感覺垃圾回收器在100萬個“廢棄”物件中只收集到了999992個。
總結:“廢棄”物件在垃圾回收時不一定會被釋放掉,執行System.gc()和System.runFinalization()可以釋放掉所有收集到的”廢棄”記憶體,單獨執行System.runFinalization()貌似無作用。
淺談一下我對System.runFinalization()和System.gc()的理解:System.runFinalization()並不是強行呼叫finalize方法,在官方文件中說的是:Java虛擬機器花費了精力來執行被發現丟棄的物件的最終方法,如果GC都沒有去收集發現,又何從執行最終方法呢!!!但是單獨呼叫System.gc()和“組合”呼叫又有釋放物件的差別:我對此的個人理解為:垃圾回收器收集到了“廢棄”的物件,並不是能收集到所有的“廢棄”,當單獨呼叫System.gc()時,從收集到的物件中釋放一部分,保證當前程序的正常執行,為什麼不釋放完,可能是因為釋放也需要佔用資源,當能保證程序執行的情況下,沒有那個必要。當組合呼叫時,System.runFinalization()呼叫垃圾回收器收集到的所有”廢棄”物件的finalize()方法。