JVM調優-Java垃圾回收之分代回收


為什么要進行分代回收?

JVM使用分代回收測試,是因為:不同的對象,生命周期是不一樣的。因此不同生命周期的對象采用不同的收集方式。
可以提高垃圾回收的效率。
Java程序運行過程中,會產生大量的對象,其中有些對象是與業務相關的。比如Http請求的Session對象,線程,Socket
連接等。但是還有一些對象,主要是程序運行過程中生成的臨時變量(比如方法中的局部變量),這些對象生命周期會比較短,
比如:String對象,由於其不變類的特性,系統會產生大量的這些對象,有些對象甚至只用一次即可回收。

試想,在不進行對象存活時間區分的情況下,每次垃圾回收都是對整個堆空間進行回收,花費時間相對會
長,同時,因為每次回收都需要遍歷所有存活對象,但實際上,對於生命周期長的對象而言,這種遍歷是沒有
效果的,因為可能進行了很多次遍歷,但是他們依舊存在。因此,分代垃圾回收采用分而治之的思想,進行代的划
分,把不同生命周期的對象放在不同代上,不同代上采用最適合它的垃圾回收方式進行回收。

如何分代

如下圖所示
虛擬機中的共划分為三個代:年輕代(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= 進行設置。

什么情況下觸發垃圾回收

由於對象進行了分代處理,因此垃圾回收區域、時間也不一樣。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()被顯示調用


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM