java架構之路-(JVM優化與原理)JVM垃圾回收算法和垃圾回收器

  接上次JVM虛擬機堆內存模型來繼續說,上次咱們主要說了何時可能把對象直接放在老年代,還有咱們的可能性分析,提出GCroot根的概念。此次咱們主要來講說垃圾回收所使用的的算法和咱們的垃圾回收器,須要瞭解咱們的可達性分析GCroot根是什麼,還有咱們的動態年齡判斷和老年代分配擔保機制,還不清楚咋回事的小夥伴能夠去我上幾篇JVM的博客去看一下,JVM內存模型的幾篇博客 http://www.javashuo.com/article/p-pvpovcun-eh.html html

  垃圾回收算法,主要就三種,標記清除,複製,標記整理。算法

標記清除:服務器

  上圖說話。多線程

 

 

 解釋一下,標記清理算法,咱們能夠視爲每個位置去觀察,可以清理就標記,不能清理就放那不動。也能夠想象爲咱們打掃屋子,咱們只扔掉咱們不想要的物品,其他想留下的東西仍是放在原處不動。併發

這種算法清理缺點是效率並不高,並且會帶來大量的空間碎片,咱們能夠由下面的小方格看到,紅色的格子不是連續的,而是分佈在不一樣位置的。這時進來一個大對象,須要多個連續的格子,就可能放不下了。優化

複製:spa

  很少了直接上圖。線程

 

 

和上面相比,咱們至少能夠看到連續的紅格子了,複製算法就是查看每個小格子,能夠回收就回收掉,不行就挪到保留的另外一半內存中去,每次只標記總體區域的一半,咱們仍是拿收拾屋子舉例,複製算法就像是,咱們把臥室收拾一遍,不要的扔掉,想留下的整齊的放在客廳,下次咱們收拾客廳也是如此,每次收拾一半。缺點就是內存利用率低,只能使用一半,還須要保留一半的區域爲了來回挪動存活對象。3d

標記整理:htm

  

 

 

 標記整理是是標記清除的升級版,優勢:解決內存碎片問題。缺點:整理階段,因爲移動了可用對象,須要去更新引用。仍是收拾屋子的那個例子,咱們把沒用的物品扔掉,其他物品整齊的擺放起來。

接下來就是和咱們回收算法對應的回收器了。

Serial收集器(-XX:+UseSerialGC -XX:+UseSerialOldGC)

Serial(串行)垃圾收集器是最基本、發展歷史最悠久的收集器;做用於新生代時採用採用複製算法;Serial Old收集器也就是Serial做用於老年代時採用標記整理算法。

採用單線程手機模式來收集。

 

 

ParNew收集器(-XX:+UseParNewGC) 

ParNew收集器其實就是Serial收集器的多線程版本,除了使用多線程進行垃圾收集外,其他行爲 (控制參數、收集算法、回收策略等等)和Serial收集器徹底同樣。默認的收集線程數跟cpu核數相同,固然也能夠用參數(-XX:ParallelGCThreads)指定收集線程數,可是通常不推薦修改。 而且單核CPU的服務器,優先考慮Serial收集器,甚至因爲存在線程交互的開銷,效果不必定強於Serial收集器,可能Serial收集器效果更好,parNew新生代採用複製算法,老年代採用標記-整理算法。 建議使用在新生代,後面會說爲何。

 

 

 

Parallel Scavenge收集器(-XX:+UseParallelGC,- XX:+UseParallelOldGC)

 Parallel Scavenge 收集器相似於ParNew 收集器,是Server 模式(內存大於2G,2個cpu)下的默認收集器, Parallel Scavenge更加關注於CPU的使用率,可能在回收的過程瞬間CPU使用率提升進行垃圾回收。Parallel Old收集器是Parallel Scavenge收集器的老年代版本。和上面的圖同樣 ,我就再也不貼圖了。新生代採用複製算法,老年代採用標記-整理算法。 

CMS收集器(-XX:+UseConcMarkSweepGC(old)) 

  相對上面幾個收集器來講稍微複雜一些,先看圖。

 由圖來看確實複雜了很多,可是並非一直處於STW階段,中間還有並行的時候。咱們來看一下每個階段都是作什麼的。

初始化標記階段:

  這裏STW時間很是短,微乎其微的,這裏只標記GCRoot根直接引用的對象,不往下層去搜索更多的對象進行標記,效率很高,STW時間很短。

併發標記階段:

  併發標記階段是最消耗時間的,在上一個階段只標記GCRoot根的直接引用對象,這個階段是把全部須要回收的對象都須要標記出來。可能引用不少,因此耗時較大。可是還好,他不會出現STW,不會停掉全部線程爲其單一服務。

從新標記階段:

  在上一個相對比龐大的併發標記階段,並無STW,可能會產生新的GCRoot根,或者說原有不須要回收的對象如今已經變爲垃圾對象了,咱們在從新標記階段再一次來作一下處理,這裏又會出現STW現象,相比並發標記階段時間也是很短的。

併發清理階段:

  恢復咱們的正常的線程,開始清理沒有標記的對象,這裏不會產生STW,在這個階段再進來的新對象,或者產生對象的變動,CMS是不會繼續處理的,會在下一次垃圾回收再來處理這些對象。

併發重置階段:

  清楚全部標記,爲下一次垃圾回收作準備。

CMS垃圾收集器步驟比較多,可是咱們能夠看出明顯提升了效率,中間至少不是持續的STW的。可是也有CMS的弊端的,併發標記階段和併發清理階段很容易和咱們正常的線程搶佔CPU的。再就是他的算法只是標記清理,並無整理內存碎片,但能夠調配參數作到整理碎片的目的。最坑的問題來了,就是咱們在併發標記階段,可能進來新的對象,原本咱們老年代就快滿了,才進行的垃圾收回,這時這些對象過大過多,會再次執行CMS的垃圾回收,形成concurrent mode failure,這時會變動爲Serial收集器,產生較長的STW時間。

CMS相關參數:

1. -XX:+UseConcMarkSweepGC:啓用cms垃圾回收器
2. -XX:ConcGCThreads:併發的GC線程數目
3. -XX:+UseCMSCompactAtFullCollection:FullGC以後作壓縮整理(減小碎片)
4. -XX:CMSFullGCsBeforeCompaction:多少次FullGC以後壓縮一次,默認是0,表明每次 FullGC後都會壓縮一次,依賴上面的參數,必須配置-XX:+UseCMSCompactAtFullCollection才生效
5. -XX:CMSInitiatingOccupancyFraction: 當老年代使用達到該比例時會觸發FullGC(默認 是92,這是百分比),可能出現JVM自我優化變動的現象,不是很穩定
6. -XX:+UseCMSInitiatingOccupancyOnly:只使用設定的回收閾值(-XX:CMSInitiatingOccupancyFraction設定的值),若是不指定,JVM僅在第一次使用設定值,後續則會自動調整,比上面的-XX:CMSInitiatingOccupancyFraction穩定不少
7. -XX:+CMSScavengeBeforeRemark:在CMS GC前啓動一次minor gc,目的在於減小 老年代對年輕代的引用,下降CMS GC的標記階段時的開銷,通常CMS的GC耗時 80%都在從新標記階段 

 

今天先說這麼多 ,還有一個G1收集器沒有說,下次博客會說G1收集器,和常見的調優方式,有時間我再整理一份經常使用的命令。

看起來真的吃力的話,建議先看一下我前幾篇JVM相關的博客,JVM內存模型的幾篇博客 http://www.javashuo.com/article/p-pvpovcun-eh.html 

最進弄了一個公衆號,小菜技術,歡迎你們的加入

相關文章
相關標籤/搜索