垃圾清理勢在必行——Java垃圾收集算法
1.Java垃圾收集算法的核心思想
Java語言建立了垃圾收集機制,用以跟蹤正在使用的對象和發(fā)現(xiàn)并回收不再使用(引用)的對象。Java垃圾回收算法可以有效防范動態(tài)內(nèi)存分配中可能發(fā)生的兩個危險:因內(nèi)存垃圾過多而引發(fā)的內(nèi)存耗盡,以及不恰當?shù)膬?nèi)存釋放所造成的內(nèi)存非法引用。
垃圾收集算法的核心思想是:對虛擬機可用內(nèi)存空間,即堆空間中的對象進行識別,如果對象正在被引用,那么稱其為存活對象,反之,如果對象不再被引用,則為垃圾對象,可以回收其占據(jù)的空間,用于再分配。垃圾收集算法的選擇和垃圾收集系統(tǒng)參數(shù)的合理調(diào)節(jié)直接影響著系統(tǒng)性能,因此需要開發(fā)人員做比較深入的了解。
2.觸發(fā)主GC(Garbage Collector)的條件
JVM進行次GC的頻率很高,但因為這種GC占用時間極短,所以對系統(tǒng)產(chǎn)生的影響不大。更值得關(guān)注的是主GC的觸發(fā)條件,因為它對系統(tǒng)影響很明顯??偟膩碚f,有兩個條件會觸發(fā)主GC:
①當應用程序空閑時,即沒有應用線程在運行時,GC會被調(diào)用。因為GC在優(yōu)先級***的線程中進行,所以當應用忙時,GC線程就不會被調(diào)用,但以下條件除外。
②Java堆內(nèi)存不足時,GC會被調(diào)用。當應用線程在運行,并在運行過程中創(chuàng)建新對象,若這時內(nèi)存空間不足,JVM就會強制地調(diào)用GC線程,以便回收內(nèi)存用于新的分配。若GC一次之后仍不能滿足內(nèi)存分配的要求,JVM會再進行兩次GC作進一步的嘗試,若仍無法滿足要求,則 JVM將報“out of memory”的錯誤,Java應用將停止。
由于是否進行主GC由JVM根據(jù)系統(tǒng)環(huán)境決定,而系統(tǒng)環(huán)境在不斷的變化當中,所以主GC的運行具有不確定性,無法預計它何時必然出現(xiàn),但可以確定的是對一個長期運行的應用來說,其主GC是反復進行的。
3.減少GC開銷的措施
根據(jù)上述GC的機制,程序的運行會直接影響系統(tǒng)環(huán)境的變化,從而影響GC的觸發(fā)。若不針對GC的特點進行設(shè)計和編碼,就會出現(xiàn)內(nèi)存駐留等一系列負面影響。為了避免這些影響,基本的原則就是盡可能地減少垃圾和減少GC過程中的開銷。具體措施包括以下幾個方面:
(1)不要顯式調(diào)用System.gc()
此函數(shù)建議JVM進行主GC,雖然只是建議而非一定,但很多情況下它會觸發(fā)主GC,從而增加主GC的頻率,也即增加了間歇性停頓的次數(shù)。
(2)盡量減少臨時對象的使用
臨時對象在跳出函數(shù)調(diào)用后,會成為垃圾,少用臨時變量就相當于減少了垃圾的產(chǎn)生,從而延長了出現(xiàn)上述第二個觸發(fā)條件出現(xiàn)的時間,減少了主GC的機會。
(3)對象不用時***顯式置為Null
一般而言,為Null的對象都會被作為垃圾處理,所以將不用的對象顯式地設(shè)為Null,有利于GC收集器判定垃圾,從而提高了GC的效率。
(4)盡量使用StringBuffer,而不用String來累加字符串(詳見blog另一篇文章JAVA中String與StringBuffer)
由于String是固定長的字符串對象,累加String對象時,并非在一個String對象中擴增,而是重新創(chuàng)建新的String對象,如Str5=Str1+Str2+Str3+Str4,這條語句執(zhí)行過程中會產(chǎn)生多個垃圾對象,因為對次作“+”操作時都必須創(chuàng)建新的String對象,但這些過渡對象對系統(tǒng)來說是沒有實際意義的,只會增加更多的垃圾。避免這種情況可以改用StringBuffer來累加字符串,因StringBuffer是可變長的,它在原有基礎(chǔ)上進行擴增,不會產(chǎn)生中間對象。
(5)能用基本類型如Int,Long,就不用Integer,Long對象
基本類型變量占用的內(nèi)存資源比相應對象占用的少得多,如果沒有必要,***使用基本變量。
(6)盡量少用靜態(tài)對象變量
靜態(tài)變量屬于全局變量,不會被GC回收,它們會一直占用內(nèi)存。
(7)分散對象創(chuàng)建或刪除的時間
集中在短時間內(nèi)大量創(chuàng)建新對象,特別是大對象,會導致突然需要大量內(nèi)存,JVM在面臨這種情況時,只能進行主GC,以回收內(nèi)存或整合內(nèi)存碎片,從而增加主GC的頻率。集中刪除對象,道理也是一樣的。它使得突然出現(xiàn)了大量的垃圾對象,空閑空間必然減少,從而大大增加了下一次創(chuàng)建新對象時強制主GC的機會??梢哉f基于Java垃圾回收算法的GC機制有效的減少了Java在內(nèi)存管理方面的錯誤。
【編輯推薦】