JVM記憶體分配與回收

  • 2020 年 3 月 12 日
  • 筆記

1.1 對象優先在Eden區分配

大多數情況下,對象在新生代中 Eden 區分配。當 Eden 區沒有足夠空間進行分配時,虛擬機將發起一次Minor GC。我們來進行實際測試一下。

在測試之前我們先來看看 Minor Gc和Full GC 有什麼不同呢?

新生代GC(Minor GC):指發生新生代的的垃圾收集動作,Minor GC非常頻繁,回收速度一般也比較快。

老年代GC(Major GC/Full GC):指發生在老年代的GC,出現了Major GC經常會伴隨至少一次的Minor GC(並非絕對),Major GC的速度一般會比Minor GC的慢10倍以上。

測試:

通過以下方式運行:

添加的參數: -XX:+PrintGCDetails

運行結果:

從上圖我們可以看出eden區記憶體幾乎已經被分配完全(即使程式什麼也不做,新生代也會使用至少2000多k記憶體)。假如我們再為allocation2分配記憶體會出現什麼情況呢?

簡單解釋一下為什麼會出現這種情況: 因為給allocation2分配記憶體的時候eden區記憶體幾乎已經被分配完了,我們剛剛講了當Eden區沒有足夠空間進行分配時,虛擬機將發起一次Minor GC.GC期間虛擬機又發現allocation1無法存入Survior空間,所以只好通過 分配擔保機制 把新生代的對象提前轉移到老年代中去,老年代上的空間足夠存放allocation1,所以不會出現Full GC。執行Minor GC後,後面分配的對象如果能夠存在eden區的話,還是會在eden區分配記憶體。可以執行如下程式碼驗證:

1.2 大對象直接進入老年代

大對象就是需要大量連續記憶體空間的對象(比如:字元串、數組)。

為什麼要這樣呢?

為了避免為大對象分配記憶體時由於分配擔保機制帶來的複製而降低效率。

1.3 長期存活的對象將進入老年代

既然虛擬機採用了分代收集的思想來管理記憶體,那麼記憶體回收時就必須能識別那些對象應放在新生代,那些對象應放在老年代中。為了做到這一點,虛擬機給每個對象一個對象年齡(Age)計數器。

如果對象在 Eden 出生並經過第一次 Minor GC 後仍然能夠存活,並且能被 Survivor 容納的話,將被移動到 Survivor 空間中,並將對象年齡設為1.對象在 Survivor 中每熬過一次 MinorGC,年齡就增加1歲,當它的年齡增加到一定程度(默認為15歲),就會被晉陞到老年代中。對象晉陞到老年代的年齡閾值,可以通過參數 -XX:MaxTenuringThreshold 來設置。

2.如何判斷對象可以被回收

堆中幾乎放著所有的對象實例,對堆垃圾回收前的第一步就是要判斷那些對象已經死亡(即不能再被任何途徑使用的對象)。

2.1 引用計數法

給對象中添加一個引用計數器,每當有一個地方引用它,計數器就加1;當引用失效,計數器就減1;任何時候計數器為0的對象就是不可能再被使用的。

這個方法實現簡單,效率高,但是目前主流的虛擬機中並沒有選擇這個演算法來管理記憶體,其最主要的原因是它很難解決對象之間相互循環引用的問題。 所謂對象之間的相互引用問題,如下面程式碼所示:除了對象objA 和 objB 相互引用著對方之外,這兩個對象之間再無任何引用。但是他們因為互相引用對方,導致它們的引用計數器都不為0,於是引用計數演算法無法通知 GC 回收器回收他們。

2.2 可達性分析演算法

這個演算法的基本思想就是通過一系列的稱為 「GC Roots」 的對象作為起點,從這些節點開始向下搜索,節點所走過的路徑稱為引用鏈,當一個對象到 GC Roots 沒有任何引用鏈相連的話,則證明此對象是不可用的。

GC Roots根節點:類載入器、Thread、虛擬機棧的本地變數表、static成員、常量引用、本地方法棧的變數等等

2.3 finalize()方法最終判定對象是否存活

即使在可達性分析演算法中不可達的對象,也並非是「非死不可」的,這時候它們暫時處於「緩刑」階段,要真正宣告一個對象死亡,至少要經歷再次標記過程。

標記的前提是對象在進行可達性分析後發現沒有與GC Roots相連接的引用鏈。

1. 第一次標記並進行一次篩選。

篩選的條件是此對象是否有必要執行finalize()方法。

當對象沒有覆蓋finalize方法,或者finzlize方法已經被虛擬機調用過,虛擬機將這兩種情況都視為「沒有必要執行」,對象被回收。

2. 第二次標記

如果這個對象被判定為有必要執行finalize()方法,那麼這個對象將會被放置在一個名為:F-Queue的隊列之中,並在稍後由一條虛擬機自動建立的、低優先順序的Finalizer執行緒去執行。這裡所謂的「執行」是指虛擬機會觸發這個方法,但並不承諾會等待它運行結束。這樣做的原因是,如果一個對象finalize()方法中執行緩慢,或者發生死循環(更極端的情況),將很可能會導致F-Queue隊列中的其他對象永久處於等待狀態,甚至導致整個記憶體回收系統崩潰。

finalize()方法是對象脫逃死亡命運的最後一次機會,稍後GC將對F-Queue中的對象進行第二次小規模標記,如果對象要在finalize()中成功拯救自己—-只要重新與引用鏈上的任何的一個對象建立關聯即可,譬如把自己賦值給某個類變數或對象的成員變數,那在第二次標記時它將移除出「即將回收」的集合。如果對象這時候還沒逃脫,那基本上它就真的被回收了。

見示常式序:

2.4 如何判斷一個常量是廢棄常量

運行時常量池主要回收的是廢棄的常量。那麼,我們如何判斷一個常量是廢棄常量呢?

假如在常量池中存在字元串 "abc",如果當前沒有任何String對象引用該字元串常量的話,就說明常量 "abc" 就是廢棄常量,如果這時發生記憶體回收的話而且有必要的話,"abc" 就會被系統清理出常量池。

2.5 如何判斷一個類是無用的類

方法區主要回收的是無用的類,那麼如何判斷一個類是無用的類的呢?

判定一個常量是否是「廢棄常量」比較簡單,而要判定一個類是否是「無用的類」的條件則相對苛刻許多。類需要同時滿足下面3個條件才能算是 「無用的類」

該類所有的實例都已經被回收,也就是 Java 堆中不存在該類的任何實例。

載入該類的 ClassLoader 已經被回收。

該類對應的 java.lang.Class 對象沒有在任何地方被引用,無法在任何地方通過反射訪問該類的方法。

虛擬機可以對滿足上述3個條件的無用類進行回收,這裡說的僅僅是「可以」,而並不是和對象一樣不使用了就會必然被回收。

3.垃圾收集演算法

3.1 標記-清除演算法

演算法分為「標記」和「清除」階段:首先標記出所有需要回收的對象,在標記完成後統一回收所有被標記的對象。它是最基礎的收集演算法,效率也很高,但是會帶來兩個明顯的問題:

效率問題

空間問題(標記清除後會產生大量不連續的碎片)

3.2 複製演算法

為了解決效率問題,「複製」收集演算法出現了。它可以將記憶體分為大小相同的兩塊,每次使用其中的一塊。當這一塊的記憶體使用完後,就將還存活的對象複製到另一塊去,然後再把使用的空間一次清理掉。這樣就使每次的記憶體回收都是對記憶體區間的一半進行回收。

3.3 標記-整理演算法

根據老年代的特點特出的一種標記演算法,標記過程仍然與「標記-清除」演算法一樣,但後續步驟不是直接對可回收對象回收,而是讓所有存活的對象向一段移動,然後直接清理掉端邊界以外的記憶體。

3.4 分代收集演算法

當前虛擬機的垃圾收集都採用分代收集演算法,這種演算法沒有什麼新的思想,只是根據對象存活周期的不同將記憶體分為幾塊。一般將java堆分為新生代和老年代,這樣我們就可以根據各個年代的特點選擇合適的垃圾收集演算法。

比如在新生代中,每次收集都會有大量對象死去,所以可以選擇複製演算法,只需要付出少量對象的複製成本就可以完成每次垃圾收集。而老年代的對象存活幾率是比較高的,而且沒有額外的空間對它進行分配擔保,所以我們必須選擇「標記-清除」或「標記-整理」演算法進行垃圾收集。

4.垃圾收集器

如果說收集演算法是記憶體回收的方法論,那麼垃圾收集器就是記憶體回收的具體實現。

雖然我們對各個收集器進行比較,但並非為了挑選出一個最好的收集器。因為直到現在為止還沒有最好的垃圾收集器出現,更加沒有萬能的垃圾收集器,我們能做的就是根據具體應用場景選擇適合自己的垃圾收集器。試想一下:如果有一種四海之內、任何場景下都適用的完美收集器存在,那麼我們的HotSpot虛擬機就不會實現那麼多不同的垃圾收集器了。

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

Serial(串列)收集器收集器是最基本、歷史最悠久的垃圾收集器了。大家看名字就知道這個收集器是一個單執行緒收集器了。它的 「單執行緒」 的意義不僅僅意味著它只會使用一條垃圾收集執行緒去完成垃圾收集工作,更重要的是它在進行垃圾收集工作的時候必須暫停其他所有的工作執行緒( "Stop The World" ),直到它收集結束。

新生代採用複製演算法,老年代採用標記-整理演算法。

虛擬機的設計者們當然知道Stop The World帶來的不良用戶體驗,所以在後續的垃圾收集器設計中停頓時間在不斷縮短(仍然還有停頓,尋找最優秀的垃圾收集器的過程仍然在繼續)。

但是Serial收集器有沒有優於其他垃圾收集器的地方呢?當然有,它簡單而高效(與其他收集器的單執行緒相比)。Serial收集器由於沒有執行緒交互的開銷,自然可以獲得很高的單執行緒收集效率。

4.2 ParNew收集器

ParNew收集器其實就是Serial收集器的多執行緒版本,除了使用多執行緒進行垃圾收集外,其餘行為(控制參數、收集演算法、回收策略等等)和Serial收集器完全一樣。

新生代採用複製演算法,老年代採用標記-整理演算法。

它是許多運行在Server模式下的虛擬機的首要選擇,除了Serial收集器外,只有它能與CMS收集器(真正意義上的並發收集器,後面會介紹到)配合工作。

並行和並發概念補充:

並行(Parallel) :指多條垃圾收集執行緒並行工作,但此時用戶執行緒仍然處於等待狀態。適合科學計算、後台處理等弱交互場景。

並發(Concurrent):指用戶執行緒與垃圾收集執行緒同時執行(但不一定是並行,可能會交替執行),用戶程式在繼續運行,而垃圾收集器運行在另一個CPU上。適合Web應用。

4.3 Parallel Scavenge收集器(-XX:+UseParallelGC(新生代),-XX:+UseParallelOldGC(老生代))

Parallel Scavenge 收集器類似於ParNew 收集器,是Server 模式(記憶體大於2G,2個cpu)下的默認收集器那麼它有什麼特別之處呢?

Parallel Scavenge收集器關注點是吞吐量(高效率的利用CPU)。CMS等垃圾收集器的關注點更多的是用戶執行緒的停頓時間(提高用戶體驗)。所謂吞吐量就是CPU中用於運行用戶程式碼的時間與CPU總消耗時間的比值。 Parallel Scavenge收集器提供了很多參數供用戶找到最合適的停頓時間或最大吞吐量,如果對於收集器運作不太了解的話,可以選擇把記憶體管理優化交給虛擬機去完成也是一個不錯的選擇。

新生代採用複製演算法,老年代採用標記-整理演算法。

4.4.Serial Old收集器

Serial收集器的老年代版本,它同樣是一個單執行緒收集器。它主要有兩大用途:一種用途是在JDK1.5以及以前的版本中與Parallel Scavenge收集器搭配使用,另一種用途是作為CMS收集器的後備方案。

4.5 Parallel Old收集器

Parallel Scavenge收集器的老年代版本。使用多執行緒和「標記-整理」演算法。在注重吞吐量以及CPU資源的場合,都可以優先考慮 Parallel Scavenge收集器和Parallel Old收集器。

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

CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時間為目標的收集器。它而非常符合在注重用戶體驗的應用上使用,它是HotSpot虛擬機第一款真正意義上的並發收集器,它第一次實現了讓垃圾收集執行緒與用戶執行緒(基本上)同時工作。

從名字中的Mark Sweep這兩個詞可以看出,CMS收集器是一種 「標記-清除」演算法實現的,它的運作過程相比於前面幾種垃圾收集器來說更加複雜一些。整個過程分為四個步驟:

初始標記: 暫停所有的其他執行緒(STW),並記錄下直接與root相連的對象,速度很快 ;

並發標記: 同時開啟GC和用戶執行緒,用一個閉包結構去記錄可達對象。但在這個階段結束,這個閉包結構並不能保證包含當前所有的可達對象。因為用戶執行緒可能會不斷的更新引用域,所以GC執行緒無法保證可達性分析的實時性。所以這個演算法里會跟蹤記錄這些發生引用更新的地方。

重新標記: 重新標記階段就是為了修正並發標記期間因為用戶程式繼續運行而導致標記產生變動的那一部分對象的標記記錄,這個階段的停頓時間一般會比初始標記階段的時間稍長,遠遠比並發標記階段時間短

並發清除: 開啟用戶執行緒,同時GC執行緒開始對未標記的區域做清掃。

從它的名字就可以看出它是一款優秀的垃圾收集器,主要優點:並發收集、低停頓。但是它有下面三個明顯的缺點:

對CPU資源敏感(會和服務搶資源);

無法處理浮動垃圾(在java業務程式執行緒與垃圾收集執行緒並發執行過程中又產生的垃圾,這種浮動垃圾只能等到下一次gc再清理了);

它使用的回收演算法-「標記-清除」演算法會導致收集結束時會有大量空間碎片產生。

CMS的相關參數

 -XX:+UseConcMarkSweepGC 啟用cms 

 -XX:ConcGCThreads:並發的GC執行緒數(並非STW時間,而是和服務一起執行的執行緒數)

 -XX:+UseCMSCompactAtFullCollection:FullGC之後做壓縮(減少碎片)

 -XX:CMSFullGCsBeforeCompaction:多少次FullGC之後壓縮一次(因壓縮非常的消耗時間,所以不能每次FullGC都做)

 -XX:CMSInitiatingOccupancyFraction:觸發FulGC條件(默認是92)

 -XX:+UseCMSInitiatingOccupancyOnly:是否動態調節

 -XX:+CMSScavengeBeforeRemark:FullGC之前先做YGC(一般這個參數是打開的)

 -XX:+CMSClassUnloadingEnabled:啟用回收Perm區(jdk1.7及以前)

4.7 G1收集器(-XX:+UseG1GC)

G1 (Garbage-First)是一款面向伺服器的垃圾收集器,主要針對配備多顆處理器及大容量記憶體的機器. 以極高概率滿足GC停頓時間要求的同時,還具備高吞吐量性能特徵.

G1將Java堆劃分為多個大小相等的獨立區域(Region),雖保留新生代和老年代的概念,但不再是物理隔閡了,它們都是(可以不連續)Region的集合。

分配大對象(直接進Humongous區,專門存放短期巨型對象,不用直接進老年代,避免Full GC的大量開銷)不會因為無法找到連續空間而提前觸發下一次GC。

被視為JDK1.7中HotSpot虛擬機的一個重要進化特徵。它具備以下特點:

並行與並發:G1能充分利用CPU、多核環境下的硬體優勢,使用多個CPU(CPU或者CPU核心)來縮短Stop-The-World停頓時間。部分其他收集器原本需要停頓Java執行緒來執行GC動作,G1收集器仍然可以通過並發的方式讓java程式繼續執行。

分代收集:雖然G1可以不需要其他收集器配合就能獨立管理整個GC堆,但是還是保留了分代的概念。

空間整合:與CMS的「標記–清理」演算法不同,G1從整體來看是基於「標記整理」演算法實現的收集器;從局部上來看是基於「複製」演算法實現的。

可預測的停頓:這是G1相對於CMS的另一個大優勢,降低停頓時間是G1 和 CMS 共同的關注點,但G1 除了追求低停頓外,還能建立可預測的停頓時間模型,能讓使用者明確指定在一個長度為M毫秒的時間片段內完成垃圾收集。

G1收集器的運作大致分為以下幾個步驟:

初始標記(initial mark,STW):在此階段,G1 GC 對根進行標記。該階段與常規的 (STW) 年輕代垃圾回收密切相關。

並發標記(Concurrent Marking):G1 GC 在整個堆中查找可訪問的(存活的)對象。

最終標記(Remark,STW):該階段是 STW 回收,幫助完成標記周期。

篩選回收(Cleanup,STW):篩選回收階段首先對各個Region的回收價值和成本進行排序,根據用戶所期望的GC停頓時間來制定回收計劃,這個階段其實也可以做到與用戶程式一起並發執行,但是因為只回收一部分Region,時間是用戶可控制的,而且停頓用戶執行緒將大幅提高收集效率。

G1收集器在後台維護了一個優先列表,每次根據允許的收集時間,優先選擇回收價值最大的Region(這也就是它的名字Garbage-First的由來)。這種使用Region劃分記憶體空間以及有優先順序的區域回收方式,保證了GF收集器在有限時間內可以儘可能高的收集效率。

G1垃圾收集分類

YoungGC

新對象進入Eden區

存活對象拷貝到Survivor區

存活時間達到年齡閾值時,對象晉陞到Old區

MixedGC

不是FullGC,回收所有的Young和部分Old(根據期望的GC停頓時間確定old區垃圾收集的優先順序)

 global concurrent marking (全局並發標記)

 Initial marking phase:標記GC Root,STW

 Root region scanning phase:標記存活Region

 Concurrent marking phase:標記存活的對象

 Remark phase :重新標記,STW

 Cleanup phase:部分STW

相關參數

 G1MixedGCLiveThresholdPercent Old區的region被回收的時候的存活對象佔比

 G1MixedGCCountTarget:一次global concurrent marking之後,最多執行Mixed GC的次數

 G1OldCSetRegionThresholdPercent  一次Mixed GC中能被選入CSet的最多old區的region數量

觸發的時機

InitiatingHeapOccupancyPercent:堆佔有率達到這個值則觸發global concurrent marking,默認45%

G1HeapWastePercent:在global concurrent marking結束之後,可以知道區有多少空間要被回收,在每次YGC之後和再次發生Mixed GC之前,會檢查垃圾佔比是否達到了此參數,只有達到了,下次才會發生Mixed GC

5. 如何選擇垃圾收集器

優先調整堆的大小讓伺服器自己來選擇

如果記憶體小於100M,使用串列收集器

如果是單核,並且沒有停頓時間的要求,串列或JVM自己選擇

如果允許停頓時間超過1秒,選擇並行或者JVM自己選

如果響應時間最重要,並且不能超過1秒,使用並發收集器

下圖有連線的可以搭配使用,官方推薦使用G1,因為性能高

6. 實戰調優

JVM調優主要就是調整下面兩個指標

停頓時間:  垃圾收集器做垃圾回收中斷應用執行的時間。  -XX:MaxGCPauseMillis

吞吐量:垃圾收集的時間和總時間的佔比:1/(1+n),吞吐量為1-1/(1+n) 。   -XX:GCTimeRatio=n

GC調優步驟

列印GC日誌

-XX:+PrintGCDetails  -XX:+PrintGCTimeStamps  -XX:+PrintGCDateStamps  -Xloggc:./gc.log

Tomcat則直接加在JAVA_OPTS變數里

分析日誌得到關鍵性指標

分析GC原因,調優JVM參數

1、Parallel Scavenge收集器(默認)

分析parallel-gc.log

調優:

第一次調優,設置Metaspace大小:增大元空間大小-XX:MetaspaceSize=64M  -XX:MaxMetaspaceSize=64M

第二次調優,增大年輕代動態擴容增量,默認是20(%),可以減少young gc:-XX:YoungGenerationSizeIncrement=30

比較下幾次調優效果:

吞吐量 最大停頓 平均停頓 Young gc Full gc

98.356%     120 ms   19 ms 19 2

 99.252%     20 ms    10 ms 16 0

99.24% 17

2、配置CMS收集器

 -XX:+UseConcMarkSweepGC

分析cms-gc.log

3、配置G1收集器

-XX:+UseG1GC

分析g1-gc.log

young GC:[GC pause (G1 Evacuation Pause) (young)

initial-mark:[GC pause (Metadata GC Threshold) (young) (initial-mark)   (參數:InitiatingHeapOccupancyPercent)

mixed GC:[GC pause (G1 Evacuation Pause) (mixed) (參數:G1HeapWastePercent)

full GC:[Full GC (Allocation Failure) (無可用region)

(G1內部,前面提到的混合GC是非常重要的釋放記憶體機制,它避免了G1出現Region沒有可用的情況,否則就會觸發Full GC事件。

CMS、Parallel、Serial GC都需要通過Full GC去壓縮老年代並在這個過程中掃描整個老年代。G1的Full GC演算法和Serial GC收集器完全一致。當一個Full GC發生時,整個Java堆執行一個完整的壓縮,這樣確保了最大的空餘記憶體可用。G1的Full GC是一個單執行緒,它可能引起一個長時間的停頓時間,G1的設計目標是減少Full GC,滿足應用性能目標。)

查看發生MixedGC的閾值:jinfo -flag InitiatingHeapOccupancyPercent 進程id

調優:

第一次調優,設置Metaspace大小:增大元空間大小-XX:MetaspaceSize=64M  -XX:MaxMetaspaceSize=64M

第二次調優,添加吞吐量和停頓時間參數:-XX:GCTimeRatio=80  -XX:MaxGCPauseMillis=100   

分析工具:gceasy,GCViewer 

G1調優相關

常用參數

 -XX:+UseG1GC 開啟G1

 -XX:G1HeapRegionSize=n,region的大小,1-32M,2048個

 -XX:MaxGCPauseMillis=200 最大停頓時間

 -XX:G1NewSizePercent   -XX:G1MaxNewSizePercent

 -XX:G1ReservePercent=10 保留防止to space溢出()

 -XX:ParallelGCThreads=n SWT執行緒數(停止應用程式)

 -XX:ConcGCThreads=n 並發執行緒數=1/4*並行

最佳實踐

年輕代大小:避免使用-Xmn、-XX:NewRatio等顯示設置Young區大小,會覆蓋暫停時間目標(常用參數3)

暫停時間目標:暫停時間不要太嚴苛,其吞吐量目標是90%的應用程式時間和10%的垃圾回收時間,太嚴苛會直接影響到吞吐量

是否需要切換到G1

 50%以上的堆被存活對象佔用

對象分配和晉陞的速度變化非常大

垃圾回收時間特別長,超過1秒

 G1調優目標

 6GB以上記憶體

停頓時間是500ms以內

吞吐量是90%以上

GC常用參數

堆棧設置

  -Xss:每個執行緒的棧大小

  -Xms:初始堆大小,默認物理記憶體的1/64

  -Xmx:最大堆大小,默認物理記憶體的1/4

  -Xmn:新生代大小

  -XX:NewSize:設置新生代初始大小

  -XX:NewRatio:默認2表示新生代占年老代的1/2,占整個堆記憶體的1/3。

  -XX:SurvivorRatio:默認8表示一個survivor區佔用1/8的Eden記憶體,即1/10的新生代記憶體。

 -XX:MetaspaceSize:設置元空間大小

  -XX:MaxMetaspaceSize:設置元空間最大允許大小,默認不受限制,JVM Metaspace會進行動態擴展。

垃圾回收統計資訊

  -XX:+PrintGC

  -XX:+PrintGCDetails

  -XX:+PrintGCTimeStamps

  -Xloggc:filename

收集器設置

  -XX:+UseSerialGC:設置串列收集器

  -XX:+UseParallelGC:設置並行收集器

  -XX:+UseParallelOldGC:老年代使用並行回收收集器

  -XX:+UseParNewGC:在新生代使用並行收集器

  -XX:+UseParalledlOldGC:設置並行老年代收集器

  -XX:+UseConcMarkSweepGC:設置CMS並發收集器

  -XX:+UseG1GC:設置G1收集器

  -XX:ParallelGCThreads:設置用於垃圾回收的執行緒數

並行收集器設置

  -XX:ParallelGCThreads:設置並行收集器收集時使用的CPU數。並行收集執行緒數。

  -XX:MaxGCPauseMillis:設置並行收集最大暫停時間

  -XX:GCTimeRatio:設置垃圾回收時間占程式運行時間的百分比。公式為1/(1+n)

  -XX:YoungGenerationSizeIncrement:年輕代gc後擴容比例,默認是20(%)

CMS收集器設置

  -XX:+UseConcMarkSweepGC:設置CMS並發收集器

  -XX:+CMSIncrementalMode:設置為增量模式。適用於單CPU情況。

  -XX:ParallelGCThreads:設置並發收集器新生代收集方式為並行收集時,使用的CPU數。並行收集執行緒數。

  -XX:CMSFullGCsBeforeCompaction:設定進行多少次CMS垃圾回收後,進行一次記憶體壓縮

  -XX:+CMSClassUnloadingEnabled:允許對類元數據進行回收

  -XX:UseCMSInitiatingOccupancyOnly:表示只在到達閥值的時候,才進行CMS回收

  -XX:+CMSIncrementalMode:設置為增量模式。適用於單CPU情況

  -XX:ParallelCMSThreads:設定CMS的執行緒數量

  -XX:CMSInitiatingOccupancyFraction:設置CMS收集器在老年代空間被使用多少後觸發

  -XX:+UseCMSCompactAtFullCollection:設置CMS收集器在完成垃圾收集後是否要進行一次記憶體碎片的整理

G1收集器設置

  -XX:+UseG1GC:使用G1收集器

  -XX:ParallelGCThreads:指定GC工作的執行緒數量

  -XX:G1HeapRegionSize:指定分區大小(1MB~32MB,且必須是2的冪),默認將整堆劃分為2048個分區

 -XX:GCTimeRatio:吞吐量大小,0-100的整數(默認9),值為n則系統將花費不超過1/(1+n)的時間用於垃圾收集

-XX:MaxGCPauseMillis:目標暫停時間(默認200ms)

  -XX:G1NewSizePercent:新生代記憶體初始空間(默認整堆5%)

  -XX:G1MaxNewSizePercent:新生代記憶體最大空間

  -XX:TargetSurvivorRatio:Survivor填充容量(默認50%)

  -XX:MaxTenuringThreshold:最大任期閾值(默認15)

 -XX:InitiatingHeapOccupancyPercen:老年代佔用空間超過整堆比IHOP閾值(默認45%),超過則執行混合收集

 -XX:G1HeapWastePercent:堆廢物百分比(默認5%)

  -XX:G1MixedGCCountTarget:參數混合周期的最大總次數(默認8)