JVM垃圾收集器(1)

此文已由做者趙計剛薪受權網易雲社區發佈。html

歡迎訪問網易雲社區,瞭解更多網易技術產品運營經驗。java


說明:垃圾回收算法是理論,垃圾收集器是回收算法的實現,關於回收算法,見《第四章 JVM垃圾回收算法算法

一、七種垃圾收集器數組

  • Serial(串行GC)-- 複製安全

  • ParNew(並行GC)-- 複製服務器

  • Parallel Scavenge(並行回收GC)-- 複製多線程

  • Serial Old(MSC)(串行GC)-- 標記-整理併發

  • CMS(併發GC)-- 標記-清除jvm

  • Parallel Old(並行GC)--標記-整理學習

  • G1(JDK1.7update14才能夠正式商用)

說明:

  • 1~3用於年輕代垃圾回收:年輕代的垃圾回收稱爲minor GC

  • 4~6用於年老代垃圾回收(固然也能夠用於方法區的回收):年老代的垃圾回收稱爲full GC

  • G1獨立完成"分代垃圾回收"

注意:並行與併發

  • 並行:多條垃圾回收線程同時操做

  • 併發:垃圾回收線程與用戶線程一塊兒操做

 

二、經常使用五種組合

  • Serial/Serial Old

  • ParNew/Serial Old:與上邊相比,只是比年輕代多了多線程垃圾回收而已

  • ParNew/CMS:當下比較高效的組合

  • Parallel Scavenge/Parallel Old:自動管理的組合

  • G1:最早進的收集器,可是須要JDK1.7update14以上

 

2.一、Serial/Serial Old:



特色:

  • 年輕代Serial收集器採用單個GC線程實現"複製"算法(包括掃描、複製)

  • 年老代Serial Old收集器採用單個GC線程實現"標記-整理"算法

  • Serial與Serial Old都會暫停全部用戶線程(即STW)

說明:

  • STW(stop the world):編譯代碼時爲每個方法注入safepoint(方法中循環結束的點、方法執行結束的點),在暫停應用時,須要等待全部的用戶線程進入safepoint,以後暫停全部線程,而後進行垃圾回收。

適用場合:

  • CPU核數<2,物理內存<2G的機器(簡單來說,單CPU,新生代空間較小且對STW時間要求不高的狀況下使用)

  • -XX:UseSerialGC:強制使用該GC組合

  • -XX:PrintGCApplicationStoppedTime:查看STW時間

 

2.二、ParNew/Serial Old:



說明:

  • ParNew除了採用多GC線程來實現複製算法之外,其餘都與Serial同樣,可是此組合中的Serial Old又是一個單GC線程,因此該組合是一個比較尷尬的組合,在單CPU狀況下沒有Serial/Serial Old速度快(由於ParNew多線程須要切換),在多CPU狀況下又沒有以後的三種組合快(由於Serial Old是單GC線程),因此使用其實很少。

  • -XX:ParallelGCThreads:指定ParNew GC線程的數量,默認與CPU核數相同,該參數在於CMS GC組合時,也可能會用到

 

2.三、Parallel Scavenge/Parallel Old:



特色:

  • 年輕代Parallel Scavenge收集器採用多個GC線程實現"複製"算法(包括掃描、複製)

  • 年老代Parallel Old收集器採用多個GC線程實現"標記-整理"算法

  • Parallel Scavenge與Parallel Old都會暫停全部用戶線程(即STW)

說明:

  •  吞吐量:CPU運行代碼時間/(CPU運行代碼時間+GC時間)

  • CMS主要注重STW的縮短(該時間越短,用戶體驗越好,因此主要用於處理不少的交互任務的狀況)

  • Parallel Scavenge/Parallel Old主要注重吞吐量(吞吐量越大,說明CPU利用率越高,因此主要用於處理不少的CPU計算任務而用戶交互任務較少的狀況)

參數設置:

  • -XX:+UseParallelOldGC:使用該GC組合

  • -XX:GCTimeRatio:直接設置吞吐量大小,假設設爲19,則容許的最大GC時間佔總時間的1/(1+19),默認值爲99,即1/(1+99)

  • -XX:MaxGCPauseMillis:最大GC停頓時間,該參數並不是越小越好

  • -XX:+UseAdaptiveSizePolicy:開啓該參數,-Xmn/-XX:SurvivorRatio/-XX:PretenureSizeThreshold這些參數就不起做用了,虛擬機會自動收集監控信息,動態調整這些參數以提供最合適的的停頓時間或者最大的吞吐量(GC自適應調節策略),而咱們須要設置的就是-Xmx,-XX:+UseParallelOldGC或-XX:GCTimeRatio兩個參數就好(固然-Xms也指定上與-Xmx相同就好)

注意:

  • -XX:GCTimeRatio和-XX:MaxGCPauseMillis設置一個就好

  • 不開啓-XX:+UseAdaptiveSizePolicy,-Xmn/-XX:SurvivorRatio/-XX:PretenureSizeThreshold這些參數依舊能夠配置,以resin服務器爲例

                <jvm-arg>-Xms2048m</jvm-arg>
                <jvm-arg>-Xmx2048m</jvm-arg>
                <jvm-arg>-Xmn512m</jvm-arg>
                <jvm-arg>-Xss1m</jvm-arg>
                <jvm-arg>-XX:PermSize=256M</jvm-arg>
                <jvm-arg>-XX:MaxPermSize=256M</jvm-arg>
                <jvm-arg>-XX:SurvivorRatio=8</jvm-arg>
                <jvm-arg>-XX:MaxTenuringThreshold=15</jvm-arg>
    
                <jvm-arg>-XX:+UseParallelOldGC</jvm-arg>
                <jvm-arg>-XX:GCTimeRatio=19</jvm-arg>
    
                <jvm-arg>-XX:+PrintGCDetails</jvm-arg>
                <jvm-arg>-XX:+PrintGCTimeStamps</jvm-arg>

適用場合:

  • 不少的CPU計算任務而用戶交互任務較少的狀況

  • 不想本身去過多的關注GC參數,想讓虛擬機本身進行調優工做

 

2.四、ParNew/CMS



說明:

  • 以上只是年老代CMS收集的過程,年輕代ParNew看"2.二、ParNew/Serial Old"就好

  • CMS是多回收線程的,不要被上圖誤導,默認的線程數:(CPU數量+3)/4

  • CMS主要注重STW的縮短(該時間越短,用戶體驗越好,因此主要用於處理不少的交互任務的狀況)

特色:

  • 年輕代ParNew收集器採用多個GC線程實現"複製"算法(包括掃描、複製)

  • 年老代CMS收集器採用多線程實現"標記-清除"算法

    • 初始標記:標記與根集合節點直接關聯的節點。時間很是短,須要STW

    • 併發標記:遍歷以前標記到的關聯節點,繼續向下標記全部存活節點。時間較長。

    • 從新標記:從新遍歷trace併發期間修改過的引用關係對象。時間介於初始標記與併發標記之間,一般不會很長。須要STW

    • 併發清理:直接清除非存活對象,清理以後,將該線程佔用的CPU切換給用戶線程

  • 初始標記與從新標記都會暫停全部用戶線程(即STW),可是時間較短;併發標記與併發清理時間較長,可是不須要STW

關於併發標記期間怎樣記錄發生變更的引用關係對象,在從新標記期間怎樣掃描這些對象,見《第六章 JVM垃圾收集器(2)

缺點:

  • 併發標記與併發清理:按照說明的第二點來說,假設有2個CPU,那麼其中有一個CPU會用於垃圾回收,而另外一個用於用戶線程,這樣的話,以前是兩CPU運行用戶線程,如今是一個,那麼效率就會急劇降低。也就是說,下降了吞吐量(即下降了CPU使用率)。

  • 併發清理:在這一過程當中,產生的垃圾沒法被清理(由於發生在從新標記以後)

  • 併發標記與併發清理:因爲是與用戶線程併發的,因此用戶線程可能會分配對象,這樣既可能對象直接進入年老代(例如,大對象),也可能進入年輕代後,年輕代發生minor GC,這樣的話,實際上要求咱們的年老代須要預留必定空間,也就是說要在年老代還有必定空間的狀況下就要進行垃圾回收,留出必定內存空間來供其餘線程使用,而不能等到年老代快爆滿了才進行垃圾回收,經過-XX:CMSInitiatingOccupancyFraction來指定當年老代空間滿了多少後進行垃圾回收,若是在回收過程當中,老年代已經不夠使用了,這時候CMS回收失敗,老年代使用serial Old進行GC

  • 標記-清理算法:會產生內存碎片,因爲是在老年代,可能會提早觸發Full GC(這正是咱們要儘可能減小的)

參數設置:

  • -XX:+UseConcMarkSweepGC:使用該GC組合

  • -XX:CMSInitiatingOccupancyFraction:指定當年老代空間滿了多少後進行垃圾回收

  • -XX:+UseCMSCompactAtFullCollection:(默認是開啓的)在CMS收集器頂不住要進行FullGC時開啓內存碎片整理過程,該過程須要STW

  • -XX:CMSFullGCsBeforeCompaction:指定多少次FullGC後才進行整理

  • -XX:ParallelCMSThreads:指定CMS回收線程的數量,默認爲:(CPU數量+3)/4

適用場合:

  • 用於處理不少的交互任務的狀況

  • 方法區的回收通常使用CMS,配置兩個參數:-XX:+CMSPermGenSweepingEnabled與-XX:+CMSClassUnloadingEnabled

 

三、一些經驗

  • 因爲當下大型企業用的比較多的仍是jdk1.6版本,因此G1用的仍是很少

  • 用得最多的兩種:ParNew/CMS和Parallel Scavenge/Parallel Old

  • Full GC的四種狀況

    • 增大survivor區

    • 增大年老區

    • 調低-XX:CMSInitiatingOccupancyFraction

    • 設置:-XX:CMSMaxAbortablePrecleanTime=5(單位:ms),防止CMS在從新標記好久後才進行併發清理

    • 增大方法區

    • 使用CMS GC回收方法區

    • 不要建立過大的對象獲數組

    • 儘可能讓對象在minor GC被回收

    • 讓對象在年輕代多存活一段時間,可能這段時間內就會被minor GC回收

    • 舊生代空間不足

    • 方法區滿了

    • CMS GC中promotion failed(minor GC時,survivor區放不下,年老區也放不下)和concurrent mode failure

    • 空間擔保機制(這一起見《深刻理解Java虛擬機(第二版)》P98)

附:具體的配置參數查看《深刻理解Java虛擬機(第二版)》P90


免費領取驗證碼、內容安全、短信發送、直播點播體驗包及雲服務器等套餐

更多網易技術、產品、運營經驗分享請點擊



相關文章:
【推薦】 Spring Boot 學習系列(10)—SpringBoot+JSP的使
【推薦】 3分鐘掌握一個有數小技能:回頭客分析
【推薦】 聊一聊整車廠的那些事——售後配件業務

相關文章
相關標籤/搜索