GC的基本原理

GC的基本原理

基礎知識
默認的虛擬機仍然是HotSpot。

(Garbage Collection,垃圾收集,垃圾回收)。

內存泄漏:用動態存儲分配函數動態開闢的空間,在使用完畢後未釋放,結果導致一直佔據該內存單元。直到程序結束。(其實說白了就是該內存空間使用完畢之後未回收)即所謂內存泄漏。
由程序申請的一塊內存,如果沒有任何一個指針指向它,那麼這塊內存就泄漏了。


內存溢出:(out of memory)通俗理解就是內存不夠。


正文:
Java的內存管理實際上就是對象的管理,其中包括對象的分配和釋放。


對於程序員來說,分配對象使用new關鍵字;釋放對象時,只要將對象所有引用賦值爲null,讓程序不能夠再訪問到這個對象,我們稱該對象爲\"不可達的\".GC將負責回收所有\"不可達\"對象的內存空間。


p = new Object();
p = null;


此時,p之前引用的對象就符合“不可達”。


詳解finalize函數
finalize是位於Object類的一個方法,該方法的訪問修飾符爲protected,
由於所有類爲Object的子類,因此用戶類很容易訪問到這個方法。
由於,finalize函數沒有自動實現鏈式調用,我們必須手動的實現,
因此finalize函數的最後一個語句通常是super.finalize()。
通過這種方式,我們可以實現從下到上實現finalize的調用,即先釋放自己的資源,然後再釋放父類的資源。


根據Java語言規範,JVM保證調用finalize函數之前,這個對象是不可達的,但是JVM不保證這個函數一定會被調用。
另外,規範還保證finalize函數最多運行一次。


很多Java初學者會認爲這個方法類似與C++中的析構函數,將很多對象、資源的釋放都放在這一函數裏面。其實,這不是一種很好的方式。
原因有三,其一,GC爲了能夠支持finalize函數,要對覆蓋這個函數的對象作很多附加的工作。其二,在finalize運行完成之後,該對象可能變成可達的,GC還要再檢查一次該對象是否是可達的。因此,使用 finalize會降低GC的運行性能。其三,由於GC調用finalize的時間是不確定的,因此通過這種方式釋放資源也是不確定的。
通常,finalize用於一些不容易控制、並且非常重要資源的釋放,例如一些I/O的操作,數據的連接。


Java2增強了內存管理功能,增加了一個java.lang.ref包,其中定義了三種引用類。這三種引用類分別爲SoftReference、WeakReference和 PhantomReference.


創建一個引用對象也非常容易,
例如如果你需要創建一個Soft Reference對象,那麼首先創建一個對象,並採用普通引用方式(可達對象);然後再創建一個SoftReference引用該對象;最後將普通引用設置爲null.通過這種方式,這個對象就只有一個Soft Reference引用。同時,我們稱這個對象爲Soft Reference 對象。
//申請一個圖像對象


Image image=new Image();//創建Image對象





//使用 image





//使用完了image,將它設置爲soft 引用類型,並且釋放強引用;


SoftReference sr=new SoftReference(image);


image=null;





//下次使用時


if (sr!=null) image=sr.get();


else{


//由於GC由於低內存,已釋放image,因此需要重新裝載;


image=new Image();


sr=new SoftReference(image);


}


Soft Reference的主要特點是據有較強的引用功能。只有當內存不夠的時候,才進行回收這類內存,因此在內存足夠的時候,它們通常不被回收。另外,這些引用對象還能保證在Java拋出OutOfMemory 異常之前,被設置爲null.它可以用於實現一些常用圖片的緩存,實現Cache的功能,保證最大限度的使用內存而不引起OutOfMemory.


Weak引用對象與Soft引用對象的最大不同就在於:GC在進行回收時,需要通過算法檢查是否回收Soft引用對象,而對於Weak引用對象,GC總是進行回收。Weak引用對象更容易、更快被 GC回收。雖然,GC在運行時一定回收Weak對象,但是複雜關係的Weak對象羣常常需要好幾次GC的運行才能完成。
Weak引用對象常常用於Map結構中,引用數據量較大的對象,一旦該對象的強引用爲null時,GC能夠快速地回收該對象空間。


Phantom引用的用途較少,主要用於輔助 finalize函數的使用。Phantom對象指一些對象,它們執行完了finalize函數,併爲不可達對象,但是它們還沒有被GC回收。這種對象可以輔助finalize進行一些後期的回收工作,我們通過覆蓋Reference的clear()方法,增強資源回收機制的靈活性。


一些Java編碼的建議
1.最基本的建議就是儘早釋放無用對象的引用。如果程序允許,儘早將不用的引用對象賦爲null.這樣可以加速GC的工作。


2.儘量少用finalize函數。finalize函數是Java提供給程序員一個釋放對象或資源的機會。但是,它會加大GC的工作量,因此儘量少採用finalize方式回收資源。


3.如果需要使用經常使用的圖片,可以使用soft引用類型。它可以儘可能將圖片保存在內存中,供程序調用,而不引起OutOfMemory.


4.注意集合數據類型,包括數組,樹,圖,鏈表等數據結構,這些數據結構對GC來說,回收更爲複雜。另外,注意一些全局的變量,以及一些靜態變量。這些變量往往容易引起懸掛對象(dangling reference),造成內存浪費。


5.當程序有一定的等待時間,程序員可以手動執行System.gc(),通知GC運行,但是Java語言規範並不保證GC一定會執行。使用增量式GC可以縮短Java程序的暫停時間。



























































發佈了79 篇原創文章 · 獲贊 8 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章