JVM調優總結:分代垃圾回收詳述

來自 http://developer.51cto.com/art/201201/311696.htm
算法

爲何要分代服務器

分代的垃圾回收策略,是基於這樣一個事實:不一樣的對象的生命週期是不同的。所以,不一樣生命週期的對象能夠採起不一樣的收集方式,以便提升回收效率。多線程

在Java程序運行的過程當中,會產生大量的對象,其中有些對象是與業務信息相關,好比Http請求中的Session對象、線程、Socket連 接,這類對象跟業務直接掛鉤,所以生命週期比較長。可是還有一些對象,主要是程序運行過程當中生成的臨時變量,這些對象生命週期會比較短,比 如:String對象,因爲其不變類的特性,系統會產生大量的這些對象,有些對象甚至只用一次便可回收。併發

試想,在不進行對象存活時間區分的狀況下,每次垃圾回收都是對整個堆空間進行回收,花費時間相對會長,同時,由於每次回收都須要遍歷全部存活對象, 但實際上,對於生命週期長的對象而言,這種遍歷是沒有效果的,由於可能進行了不少次遍歷,可是他們依舊存在。所以,分代垃圾回收採用分治的思想,進行代的 劃分,把不一樣生命週期的對象放在不一樣代上,不一樣代上採用最適合它的垃圾回收方式進行回收。spa

如何分代線程

如圖所示:htm

虛擬機中的共劃分爲三個代:年輕代(Young Generation)、年老點(Old Generation)和持久代(Permanent Generation)。其中持久代主要存放的是Java類的類信息,與垃圾收集要收集的Java對象關係不大。年輕代和年老代的劃分是對垃圾收集影響比 較大的。對象

年輕代:生命週期

全部新生成的對象首先都是放在年輕代的。年輕代的目標就是儘量快速的收集掉那些生命週期短的對象。年輕代分三個區。一個Eden區,兩個 Survivor區(通常而言)。大部分對象在Eden區中生成。當Eden區滿時,還存活的對象將被複制到Survivor區(兩個中的一個),當這個 Survivor區滿時,此區的存活對象將被複制到另一個Survivor區,當這個Survivor去也滿了的時候,從第一個Survivor區複製 過來的而且此時還存活的對象,將被複制「年老區(Tenured)」。須要注意,Survivor的兩個區是對稱的,沒前後關係,因此同一個區中可能同時 存在從Eden複製過來 對象,和從前一個Survivor複製過來的對象,而複製到年老區的只有從第一個Survivor去過來的對象。並且,Survivor區總有一個是空 的。同時,根據程序須要,Survivor區是能夠配置爲多個的(多於兩個),這樣能夠增長對象在年輕代中的存在時間,減小被放到年老代的可能。內存

年老代:

在年輕代中經歷了N次垃圾回收後仍然存活的對象,就會被放到年老代中。所以,能夠認爲年老代中存放的都是一些生命週期較長的對象。

持久代:

用於存放靜態文件,現在Java類、方法等。持久代對垃圾回收沒有顯著影響,可是有些應用可能動態生成或者調用一些class,例如 Hibernate等,在這種時候須要設置一個比較大的持久代空間來存放這些運行過程當中新增的類。持久代大小經過-XX:MaxPermSize=& lt;N>進行設置。

什麼狀況下觸發垃圾回收

因爲對象進行了分代處理,所以垃圾回收區域、時間也不同。GC有兩種類型:Scavenge GC和Full GC。

Scavenge GC

通常狀況下,當新對象生成,而且在Eden申請空間失敗時,就會觸發Scavenge GC,對Eden區域進行GC,清除非存活對象,而且把尚且存活的對象移動到Survivor區。而後整理Survivor的兩個區。這種方式的GC是對 年輕代的Eden區進行,不會影響到年老代。由於大部分對象都是從Eden區開始的,同時Eden區不會分配的很大,因此Eden區的GC會頻繁進行。因 而,通常在這裏須要使用速度快、效率高的算法,使Eden去能儘快空閒出來。

Full GC

對整個堆進行整理,包括Young、Tenured和Perm。Full GC由於須要對整個對進行回收,因此比Scavenge GC要慢,所以應該儘量減小Full GC的次數。在對JVM調優的過程當中,很大一部分工做就是對於FullGC的調節。有以下緣由可能致使Full GC:

 年老代(Tenured)被寫滿

持久代(Perm)被寫滿

System.gc()被顯示調用

上一次GC以後Heap的各域分配策略動態變化

分代垃圾回收流程示意

 

 

 

 

選擇合適的垃圾收集算法

串行收集器

用單線程處理全部垃圾回收工做,由於無需多線程交互,因此效率比較高。可是,也沒法使用多處理器的優點,因此此收集器適合單處理器機器。固然,此收集器也能夠用在小數據量(100M左右)狀況下的多處理器機器上。可使用-XX:+UseSerialGC打開。

並行收集器

對年輕代進行並行垃圾回收,所以能夠減小垃圾回收時間。通常在多線程多處理器機器上使用。使用-XX:+UseParallelGC.打開。並行收 集器在J2SE5.0第六6更新上引入,在Java SE6.0中進行了加強--能夠對年老代進行並行收集。若是年老代不使用併發收集的話,默認是使用單線程進行垃圾回收,所以會制約擴展能力。使用 -XX:+UseParallelOldGC打開。

使用-XX:ParallelGCThreads=<N>設置並行垃圾回收的線程數。此值能夠設置與機器處理器數量相等。

此收集器能夠進行以下配置:
 

最大垃圾回收暫停:指定垃圾回收時的最長暫停時間,經過-XX:MaxGCPauseMillis=<N>指定。<N>爲毫秒.若是指定了此值的話,堆大小和垃圾回收相關參數會進行調整以達到指定值。設定此值可能會減小應用的吞吐量。

吞吐量:吞吐量爲垃圾回收時間與非垃圾回收時間的比值,經過-XX:GCTimeRatio=<N>來設定,公式爲1/(1+N)。例如,-XX:GCTimeRatio=19時,表示5%的時間用於垃圾回收。默認狀況爲99,即1%的時間用於垃圾回收。

併發收集器

能夠保證大部分工做都併發進行(應用不中止),垃圾回收只暫停不多的時間,此收集器適合對響應時間要求比較高的中、大規模應用。使用-XX:+UseConcMarkSweepGC打開。

併發收集器主要減小年老代的暫停時間,他在應用不中止的狀況下使用獨立的垃圾回收線程,跟蹤可達對象。在每一個年老代垃圾回收週期中,在收集初期併發 收集器 會對整個應用進行簡短的暫停,在收集中還會再暫停一次。第二次暫停會比第一次稍長,在此過程當中多個線程同時進行垃圾回收工做。

併發收集器使用處理器換來短暫的停頓時間。在一個N個處理器的系統上,併發收集部分使用K/N個可用處理器進行回收,通常狀況下1<=K<=N/4。

在只有一個處理器的主機上使用併發收集器,設置爲incremental mode模式也可得到較短的停頓時間。

浮動垃圾:因爲在應用運行的同時進行垃圾回收,因此有些垃圾可能在垃圾回收進行完成時產生,這樣就形成了「Floating Garbage」,這些垃圾須要在下次垃圾回收週期時才能回收掉。因此,併發收集器通常須要20%的預留空間用於這些浮動垃圾。

Concurrent Mode Failure:併發收集器在應用運行時進行收集,因此須要保證堆在垃圾回收的這段時間有足夠的空間供程序使用,不然,垃圾回收還未完成,堆空間先滿了。這種狀況下將會發生「併發模式失敗」,此時整個應用將會暫停,進行垃圾回收。

啓動併發收集器:由於併發收集在應用運行時進行收集,因此必須保證收集完成以前有足夠的內存空間供程序使用,否 則會出現「Concurrent Mode Failure」。經過設置-XX:CMSInitiatingOccupancyFraction=<N>指定還有多少剩餘堆時開始執行並 發收集。

小  結

串行處理器

◆  適用狀況:數據量比較小(100M左右);單處理器下而且對響應時間無要求的應用。

◆ 缺點:只能用於小型應用。

並行處理器:

◆ 適用狀況:「對吞吐量有高要求」,多CPU、對應用響應時間無要求的中、大型應用。舉例:後臺處理、科學計算。
◆ 缺點:垃圾收集過程當中應用響應時間可能加長。

併發處理器:

◆ 適用狀況:「對響應時間有高要求」,多CPU、對應用響應時間有較高要求的中、大型應用。舉例:Web服務器/應用服務器、電信交換、集成開發環境。

相關文章
相關標籤/搜索