java物件生命週期
物件的整個生命週期大致可以分為7個階段:建立階段(Creation)、應用階段(Using)、不可視階段(Invisible)、不可到達階段(Unreachable)、可收集階段(Collected)、終結階段(Finalized)與釋放階段(Free)。
建立階段
一個Java類(除Object類外)至少有一個父類(Object),這個規則既是強制的,也是隱式的。你可能已經注意到在建立一個Java類的時候,並沒有顯式地宣告擴充套件(extends)一個Object父類。
public class A {
…
}
這個宣告等同於下面的宣告:
public class A extends java.lang.Object {
…
}
建立物件時應該遵循的規則
避免在迴圈體中建立物件,即使該物件佔用記憶體空間不大。
for (int i = 0; i < 10000; ++i) {
Object obj = new Object();
System.out.println("obj= "+ obj);
}
上面這種寫法違法了該規則,會浪費大量空間。
Object obj = null;
for (int i = 0; i < 10000; ++i) {
obj = new Object();
System.out.println("obj= "+ obj);
}
這種寫法,僅在記憶體中儲存一份對該物件的引用,而不像上面的第一種編寫方式中程式碼會在記憶體中產生大量的物件應用,浪費大量的記憶體空間,而且增大了系統做垃圾回收的負荷。
不要對一個物件進行多次初始化,這同樣會帶來較大的記憶體開銷,降低系統效能。
應用階段
強引用
強引用(Strong Reference)是指JVM記憶體管理器從根引用集合(Root Set)出發遍尋堆中所有到達物件的路徑。當到達某物件的任意路徑都不含有引用物件時,對這個物件的引用就被稱為強引用。
軟引用
軟引用(Soft Reference)的主要特點是具有較強的引用功能。只有當記憶體不夠的時候,才回收這類記憶體,因此在記憶體足夠的時候,它們通常不被回收。
import java.lang.ref.SoftReference;
…
A a = new A();
…
// 使用 a
…
// 使用完了a,將它設定為soft 引用型別,並且釋放強引用;
SoftReference sr = new SoftReference(a);
a = null;
…
// 下次使用時
if (sr!=null) {
a = sr.get();
}
else{
// GC由於記憶體資源不足,可能系統已回收了a的軟引用,
// 因此需要重新裝載。
a = new A();
sr=new SoftReference(a);
}
弱引用
GC在進行回收時,需要透過演算法檢查是否回收Soft引用物件,而對於Weak引用物件, GC總是進行回收。因此Weak引用物件會更容易、更快被GC回收。
import java.lang.ref.WeakReference;
…
A a = new A();
…
// 使用 a
…
// 使用完了a,將它設定為weak 引用型別,並且釋放強引用;
WeakReference wr = new WeakReference (a);
a = null;
…
// 下次使用時
if (wr!=null) {
a = wr.get();
}
else{
a = new A();
wr = new WeakReference (a);
}
虛引用
虛引用(Phantom Reference)的用途較少,主要用於輔助finalize函式的使用。Phantom物件指一些執行完了finalize函式,並且為不可達物件,但是還沒有被GC回收的物件。
不可視階段
public void process () {
try {
Object obj = new Object();
obj.doSomething();
} catch (Exception e) {
e.printStackTrace();
}
while (isLoop) { // ... loops forever
// 這個區域對於obj物件來說已經是不可視的了
// 因此下面的程式碼在編譯時會引發錯誤
obj.doSomething();
}
}
如果一個物件已使用完,而且在其可視區域不再使用,此時應該主動將其設定為空(null)。可以在上面的程式碼行obj.doSomething();下新增程式碼行obj = null;,這樣一行程式碼強制將obj物件置為空值。這樣做的意義是,可以幫助JVM及時地發現這個垃圾物件,並且可以及時地回收該物件所佔用的系統資源。
不可到達階段
在虛擬機器所管理的物件引用根集合中再也找不到直接或間接的強引用,這些物件通常是指所有執行緒棧中的臨時變數,所有已裝載的類的靜態變數或者對原生代碼介面(JNI)的引用。這些物件都是要被垃圾回收器回收的預備物件,但此時該物件並不能被垃圾回收器直接回收。其實所有垃圾回收演算法所面臨的問題是相同的——找出由分配器分配的,但是使用者程式不可到達的記憶體塊。
可收集階段、終結階段與釋放階段
垃圾回收器發現該物件已經不可到達。
finalize方法已經被執行。
物件空間已被重用。
當物件處於上面的三種情況時,該物件就處於可收集階段、終結階段與釋放階段了。虛擬機器就可以直接將該物件回收了。