1. 程式人生 > >Java中的物件與垃圾回收機制

Java中的物件與垃圾回收機制

物件在記憶體中的狀態

當一個物件在堆記憶體中執行時,根據它被引用變數所引用的狀態,可以把它所處的狀態分為如下三種。

  • 可達狀態:當一個物件被建立之後,若有一個以上的引用變數引用它,則這個物件在程式中處於可達狀態,程式可以通過引用變數來呼叫該物件的例項變數和方法。
  • 可恢復狀態:如果程式中某個物件不再有任何引用變數引用它,他就進入可恢復狀態。在這種狀態下,系統的垃圾回收機制準備回收該物件所佔有的記憶體,在回收該物件之前,系統會呼叫所有可恢復狀態和物件的finalize()方法進行資源清理。如果系統再呼叫finalize()方法時重新讓一個引用變數引用該物件,則這個物件會再次為可達狀態;否則該物件進入不可達狀態。
  • 不可達狀態:當物件與所有引用變數的關聯都被切斷,且系統已經呼叫所有物件的finalize()方法後依然沒有使該物件變成可達狀態,那麼這個物件將永久性的失去引用,最後變成不可達狀態,只有當一個物件處於不可達狀態時,系統才會真正的回收該物件所佔有的資源。 

 finalize方法

在垃圾回收機制回收某個物件所佔用的記憶體之前,通常要求程式呼叫適當的方法來清理資源,在沒有明確指定清理資源的情況下,java提供了預設機制來清理該物件的資源,這個機制就是finalize()方法。

finalize()方法具有以下四個特點

  • 永遠不要主動呼叫某個物件的finalize()方法,該方法應該交給垃圾回收機制呼叫。
  • finalize()方法何時被呼叫,是否被呼叫具有不確定性,不要把finalize()方法當成一定會被執行的方法。
  • 當JVM執行可恢復物件的finalize()方法時,可能使該物件或系統中其他物件重新變成可達狀態。
  • 當JVM執行finalize()方法時出現異常時,垃圾回收機制不會報告異常,程式繼續執行。

 強制垃圾回收

 當一個物件失去引用後,系統何時呼叫它的finalize()方法對它進行資源清理,何時他會變成不可達狀態,系統何時回收它所佔有的記憶體,對於程式完全是透明。因此程式無法精確控制java垃圾回收的時機,但依然可以強制系統進行垃圾回收-----這種的強制只是通知系統進行垃圾回收,但系統是否進行垃圾回收依然不確定。大部分時候,程式強制系統垃圾回收後總會有一些效果。強制系統垃圾回收有如下兩個方式。

  • 呼叫System類的gc()靜態方法:System.gc()。
  • 呼叫Runtime物件的gc()例項方法:Runtime.getRuntime().gc()。

物件的軟、弱和虛引用

對於大部分物件而言,程式裡會有一個引用變數引用該物件,這是最常見的引用方式。初次之外,java.lang.ref包下提供了3個類:SoftReference、PhantomReference和WeakReference,他們代表了系統物件的3種引用方式:軟引用、虛引用和弱引用。因此java語言對物件的引用有如下4種方式。

  1. 強引用(StrongReference) :這是java程式中最常見的引用方式。程式建立一個物件,並把這個對賦給一個引用變數,程式通過該引用變數來操作實際的物件,前面介紹的物件和陣列都是採用了這種強引用的方式。當一個物件被一個或一個以上的引用變數所引用時,它處於可達狀態,不可以被系統的垃圾回收機制回收。
  2. 軟引用(SoftReference):軟引用需要通過SoftReferece類實現,當一個物件只有軟引用的時候,它有可能被垃圾回收機制回收。對於只有段引用的物件而言,當系統記憶體足夠時,它不會被系統回收,程式也有可能使用該物件;當系統的記憶體不足時,系統可能會回收它。軟引用通常用於對記憶體敏感的程式中。
  3. 弱引用(WeakReference):弱引用通過WeakReference類實現,弱引用和軟引用很像,但弱引用的引用級別更低。對於只有弱引用的物件而言,當系統垃圾回收機制執行時,不管系統記憶體是是否夠,總會回收該物件佔用的記憶體。當然,並不是說當一個物件是弱引用時,他就會立即被回收------正如那些失去引用的物件一樣,必須等到系統垃圾回收機制執行的時候才會被回收。
  4. 虛引用(PhantomReference):虛引用通過PhantomReference類實現,虛引用完全類似於沒有引用。虛引用對物件本身沒有太大的影響,物件甚至感覺不到虛引用的存在。如果一個物件只有一個虛引用的時候,那麼它共和沒有引用的效果大致相同。虛引用主要用於跟蹤物件被垃圾回收的狀態,虛引用不能單獨使用,虛引用必須和引用佇列(ReferenceQueue)聯合使用。