java的對象與垃圾回收機制

摘要: java 的垃圾回收是 java 語言的重要功能之一。當程序創建對象、數組等引用類型實體時,系統會在堆內存中位置分配一塊內存區,對象就保存在這塊內存區中,當這塊內存不在被任何變量引用時,這塊內存就變成垃圾,等待垃圾回收機制進行回收。

java 的垃圾回收是 java 語言的重要功能之一。當程序創建對象、數組等引用類型實體時,系統會在堆內存中位置分配一塊內存區,對象就保存在這塊內存區中,當這塊內存不在被任何變量引用時,這塊內存就變成垃圾,等待垃圾回收機制進行回收。垃圾回收機制具有如下特徵。

垃圾回收機制只負責回收堆內存中的對象,不會回收任何物理資源(例如數據庫連接,網絡等資源)
程序無法控制垃圾回收的運行,垃圾回收會在合適的時候進行。當對象永久性的失去引用後,系統會在合適的時候回收它佔用的內存。
在垃圾回收機制回收任何對象之前,總會先調用它的finalize()方法,該方法可能會使該對象重新復活(讓一個引用變量引用該對象),從而導致垃圾回收機制取消回收。
對象在內存中的狀態
當一個對象在堆內存中運行時,根據它被引用變量引用的狀態,可以把它所處的狀態分成如下三種。
可達狀態:當一個對象被創建後,若有一個以上的引用變量引用它,則這個對象在程序中處於可達狀態,程序可通過引用變量來調用該對象的實例變量和方法。
可恢復狀態:如果程序中某個對象不再有任何變量引用它,它就進入了可恢復狀態。在這種狀態下,系統的垃圾回收機制準備回收該對象的所佔用的內存,再回收該對象之前,系統會調用所有可恢復狀態對象的finalize()方法進行資源清理。如果系統在調用 finalize() 方法時重新讓一個引用變量引用該對象,則這個對象會再次變爲可達狀態;否則該對象進入不可達狀態。
不可達狀態:當對象與所有引用變量的聯繫被切斷,且系統已經調用所有對象的finalize()方法後依然沒有使該對象變成可達狀態,系統會回收該對象所佔有的資源。
強制垃圾回收
程序只能控制一個對象何時不再被任何引用變量引用,絕不能控制它何時被回收。
程序無法精確控制 java 垃圾回收的時機,但依然可以強制系統進行垃圾回收——這種強制只是通知系統進行垃圾回收,但系統是否進行垃圾回收依然不確定。大部分時候,程序強制系統進行垃圾回收總會有一些效果。有兩種方式。
調用 System 類的 gc() 靜態方法:System.gc() 。
調用 Runtime 對象的 gc() 實例方法:Runtime.getRuntime().gc() 。
finalize() 方法
在垃圾回收機制回收某個對象所佔用內存之前。通常要求程序調用合適的方法來處理資源,在沒有明確指定清理資源的情況下,java提供了默認機制來清理該對象的資源。這個機制就是 finallize() 方法。該方法是定義在 Object 的實例方法,方法原型爲:

protected void finalize() throws Throwable

finalize() 方法具有如下四個特點:
永遠不要主動調用某個對象的 finalize() 方法,該方法應該交給垃圾回收機制調用
finalize() 方法何時被調用,是否被調用具有不確定性,不要把finalize()方法當成一定會被執行的方法
當 JVM 執行可恢復對象的 finalize() 方法時,可能使該對象或系統中的其他對象重新變成可達狀態
當 JVM 執行finalize() 方法出現異常時,垃圾回收機制不會報告異常,程序繼續執行
對象的軟、弱和虛引用
對大部分對象而言,程序裏會有一個引用變量引用該對象,這是最常見的引用方式。除此之外,java.lang.ref 下提供了3個類:SoftReference、PhanTomRerence 和 WeakReference ,他們分別代表了系統對對象的 3 種引用方式:軟引用、虛引用和弱引用。因此,java 的對象引用有四種方式:
強引用
這是java程序中最常見的引用方式。程序創建一個對象,並把這個對象賦給一個引用變量,程序通過引用變量操作實際的對象
軟引用
軟引用需要通過 SoftReference 類來實現,當一個對象只有軟引用時,它有可能被垃圾回收機制回收。對於只有軟引用的對象而言,當系統內存空間足夠時,它不會被系統回收,程序也可使用該對象。當系統內存空間不足時,系統可能會回收它。軟引用通常用於對內存敏感的程序中。
弱引用
虛引用通過 WeakReference 來實現,弱引用跟軟引用很像,但弱引用的引用級別更低,對於弱引用的對象而言,當系統垃圾回收機制運行時,不管系統內存是否足夠,總會回收該對象所佔用的資源。
虛引用
虛引用通過PhantomReference 類來實現,虛引用完全類似於沒有引用。虛引用對對象本身沒有太大影響,對象甚至感覺不到虛引用的存在。虛引用主要用於跟蹤對象被垃圾回收的狀態,虛引用不能被單獨使用,必須和引用隊列(ReferenceQueue) 聯合使用

上面三個引用類都包含一個get方法,用於獲取它們所引用的對象。下面程序示範了弱引用的對象被系統垃圾回收的過程

public class PhantomRefenceTest {
public static void main(String[] args) {
// 創建一個字符串對象
String str = new String("奇俠闖天下");
// 創建一個引用隊列
ReferenceQueue rq =new ReferenceQueue();
PhantomReference pr = new PhantomReference(str,rq);
str = null;
//虛引用無法獲取它的對象,即使對象還沒被回收,輸出爲 null
System.out.println(pr.get());
//強制垃圾回收
System.gc();
System.runFinalization();
// 垃圾回收之後,虛引用將被放入引用隊列中
// 取出引用隊列中最先進入隊列的引用於pr進行比較
System.out.println(rq.poll() == pr);
}
}

取出被引用對象的方式

// 取出弱引用所引用的對象
obj = wr.get();
// 如果取出的對象爲null
if(obj == null) {
//重新創建一個對象,並使用強引用引用他
obj = recreateIt();
// 取出弱引用引用的對象,將其賦給 obj 變量
wr = new WeakReference(obj);
}請添加鏈接描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章