1. 程式人生 > >深入淺出 JVM GC(4)常用 GC 參數介紹

深入淺出 JVM GC(4)常用 GC 參數介紹

分配 很快 wait 占用率 loading lena 建議 amp 試圖

技術分享圖片

# 前言

從前面的3篇文章中,我們分析了5個垃圾收集器,還有一些 GC 的算法,那麽,在 GC 調優中,我們肯定會先判斷哪裏出現的問題,然後再根據出現的問題進行調優,而調優的手段就是 JVM 提供給我們的那些參數或者說選項,這些參數將會改變 GC 的運行方式。因此,他們顯得極為重要。

我們將每一個垃圾收集器相關的參數一個一個娓娓道來,註意,樓主推薦一個小程序:前阿裏 JVM 大神寒泉子的公眾號裏面有個小程序------JVM Pocket,這個小程序介紹了所有的 JVM 參數的作用,你可以在裏面搜索你想知道的參數,也可以把你了解的參數寫上去供大家參考。公眾號:lovestblog。

值得註意的一點是,這些參數可能會重復,還記得我們之前的那張圖嗎,樓主覺得有必要再發一次:

技術分享圖片

可以看到,這些收集器會有一些重復,而且,某些參數也是會作用於所有的處理器,因此,我們下面的介紹可能會有一些重復。

還有一點就是,JVM 為我們設置了很多默認的參數,但是,如果可以的話,還是建議使用顯式的聲明,這樣更能表達意圖。否則,別人不一定知道我們是否知道這些默認值。

我們開始我們的參數之旅吧!

# 1. Serial 收集器參數

串行收集器,client 的默認收集器,分為年輕代 Serial 和老年代 Serial Old 收集器。

  1. -XX:+UseSerialGC 這個參數就是可以指定使用新生代串行收集器和老年代串行收集器, “+” 號的意思是ture,開啟,反之,如果是 “-”號,則是關閉。

  2. -XX:+UseParNewGC 新生代使用 ParNew 回收器,老年代使用串行收集器。

  3. -XX:+UseParallelGC 新生代私用 ParallelGC 回收器,老年代使用串行收集器。

而 Serial 收集器出現的日誌為 DefNew .

# 2. ParNew 收集器參數

並行收集器是 Serial 的多線程版本,在 CPU 並行能力強大的計算機上有很大優勢。

其中:

  1. -XX:+UseParNewGC 上面說過了,新生代使用 ParNew 收集器,老年代使用串行收集器。

  2. -XX:+UseConcMarkSweepGC: 新生代使用 ParNew 回收器,老年代使用 CMS。

  3. -XX:ParallelGCThreads={value} 這個參數是指定並行 GC 線程的數量,一般最好和 CPU 核心數量相當。默認情況下,當 CPU 數量小於8, ParallelGCThreads 的值等於 CPU 數量,當 CPU 數量大於 8 時,則使用公式:3+((5*CPU)/ 8);同時這個參數只要是並行 GC 都可以使用,不只是 ParNew。

而 ParNew 的 GC 日誌則表吸納出 ParNew。

# 3. PS 收集器參數

全稱 Parallel Scavenge 收集器,該收集器是 Java 8 的默認收集器,因為它能夠根據系統當前狀態給出吞吐量最高的GC 配置。所以,在一些手工調優復雜的場合或者對實時性要求不高的場合,可以使用該處理器。

有哪些參數呢?

  1. -XX:MaxGCPauseMillis 設置最大垃圾收集停頓時間,他的值是一個大於0的整數。ParallelGC 工作時,會調整 Java 堆大小或者其他的一些參數,盡可能的把停頓時間控制在 MaxGCPauseMillis 以內。如果為了將停頓時間設置的很小,將此值也設置的很小,那麽 PS 將會把堆設置的也很小,這將會到值頻繁 GC ,雖然系統停頓時間小了,但總吞吐量下降了。

  2. -XX:GCTimeRatio 設置吞吐量大小,他的值是一個0 到100之間的整數,假設 GCTimeRatio 的值是 n ,那麽系統將花費不超過 1/(1+n) 的時間用於垃圾收集,默認 n 是99,即不超過1% 的時間用於垃圾收集。

  3. -XX:+UseParallelGC 新生代使用 ParallelGC 回收器,老年代使用串行回收器。

  4. -XX:+UseParallelOldGC 新生代使用 ParallelGC 回收器,老年代使用 ParallelOldGC 回收器。

  5. -XX:UseAdaptiveSizePolicy: 打開自適應策略。在這種模式下,新生代的大小,eden 和 Survivor 的比例,晉升老年代的對象年齡等參數會被自動調整。以達到堆大小,吞吐量,停頓時間的平衡點。

聰明的同學相比看出來了,1 和 2 兩個參數是矛盾的。因為吞吐量和停頓時間就是矛盾的。所以,要根據應用的特性來進行設置,以達到最優水平。

同時,Parallel Old 收集器也是一種關註吞吐量的並行的老年代回收器。

  1. -XX:+UseParallelOldGC 新生代使用 ParallelGC 回收器,老年代使用 ParallelOldGC 回收器。該參數可以啟用 ParallelOldGC。

  2. -XX:ParallelGCGThreads 同時可以指定該參數設置並行線程數量。

而 PS 處理器的 GC 日誌則是 PSYoungGen。

# 4. CMS 收集器參數

CMS 處理器關註的是停頓時間。全稱 Concurrent Mark Sweep。因為該處理器較為復雜,因此可以使用較多參數。

  1. -XX:-CMSPrecleaningEnabled 不進行預清理,度過我們之前的文章的都知道,CMS 在並發標記和重新標記的這段時間內,會有一個預清理的工作,而這個通過會嘗試5秒之內等待來一次 YGC。以免在後面的重新標記階段耗費大量時間來標記新生代的對象。

  2. -XX:+UseConcMarkSweepGC 此參數將啟動 CMS 回收器。默認新生代是 ParNew,也可以設置 Serial 為新生代收集器。該參數等價於 -Xconcgc。

  3. -XX:ParallelGCThreads 由於是並行處理器,當然也可以指定線程數。默認並發線程數是:(ParallelGCThreads + 3)/ 4)。

  4. -XX:ConcGCThreads 或者 -XX:ParallelCMSThreads ;除了上面設置線程的方式,你也可以通過這個兩個參數任意一個手工設定 CMS 並發線程數。

  5. -XX:CMSInitiatingOccupancyFraction 由於 CMS 回收器不是獨占式的,在垃圾回收的時候應用程序仍在工作,所以需要留出足夠的內存給應用程序,否則會觸發 FGC。而什麽時候運行 CMS GC 呢?通過該參數即可設置,該參數表示的是老年代的內存使用百分比。當達到這個閾值就會執行 CMS。默認是68。 如果老年代內存增長很快,建議降低閾值,避免 FGC,如果增長慢,則可以加大閾值,減少 CMS GC 次數。提高吞吐量。

  6. -XX:+UseCMSCompactAtFullCollection 由於 CMS 使用標記清理算法,內存碎片無法避免。該參數指定每次 CMS 後進行一次碎片整理。

  7. -XX:CMSFullGCsBeforeCompaction 由於每次進行碎片整理將會影響性能,你可以使用該參數設定多少次 CMS 後才進行一次碎片整理,也就是內存壓縮。

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

  9. -XX:CMSInitiatingPermOccupancyFraction 當永久區占用率達到這一百分比時,啟動 CMS 回收(前提是 -XX:+CMSClassUnloadingEnabled 激活了)。

  10. -XX:UseCMSInitiatingOccupancyOnly 表示只在到達閾值的時候才進行 CMS 回收。

  11. XX:CMSWaitDuration=2000 由於CMS GC 條件比較簡單,JVM有一個線程定時掃描Old區,時間間隔可以通過該參數指定(毫秒單位),默認是2s。

CMS 的 GC 日誌 就是 CMS。

# 5. G1 收集器參數

作為 Java 9 的默認垃圾收集器,該收集器和之前的收集器大不相同,該收集器可以工作在young 區,也可以工作在 old 區。有哪些參數呢?

  1. -XX:+UseG1GC 開啟 G1 收集器。

  2. -XX:MaxGCPauseMillis 用於指定最大停頓時間,如果任何一次停頓超過這個設置值時,G1 就會嘗試調整新生代和老年代的比例,調整堆大小,調整晉升年齡的手段,試圖達到目標。和 PS 一樣,停頓時間小了,對應的吞吐量也會變小。這點值得註意。

  3. -XX:ParallelGCThreads 由於是並行並發的,可以指定GC 工作線程數量。

  4. -XX:InitiatingHeapOccupancyPercent 該參數可以指定當整個堆使用率達到多少時,觸發並發標記周期的執行。默認值時45,即當堆的使用率達到45%,執行並發標記周期,該值一旦設置,始終都不會被 G1修改。也就是說,G1 就算為了滿足 MaxGCPauseMillis 也不會修改此值。如果該值設置的很大,導致並發周期遲遲得不到啟動,那麽引起 FGC 的幾率將會變大。如果過小,則會頻繁標記,GC 線程搶占應用程序CPU 資源,性能將會下降。

  5. -XX:GCPauseIntervalMillis 設置停頓時間間隔。

# 6. 一些通用參數

在 GC 調優中,還有一些通用的參數。通常是我們的好幫手。

  1. -XX:-+DisableExplicitGC 禁用 System.gc(),由於該方法默認會觸發 FGC,並且忽略參數中的 UseG1GC 和 UseConcMarkSweepGC,因此必要時可以禁用該方法。

  2. -XX:+ExplicitGCInvokesConcurrent 該參數可以改變上面的行為,也就是說,System.gc() 後不使用 FGC ,而是使用配置的並發收集器進行並發收集。註意:使用此選項就不要 使用 上面的選項。

  3. -XX:-ScavengeBeforeFullGC 由於大部分 FGC 之前都會 YGC,減輕了 FGC 的壓力,縮短了 FGC 的停頓時間,但也可能你不需要這個特性,那麽你可以使用這個參數關閉,默認是 ture 開啟。

  4. -XX:MaxTenuringThreshold={value} 新生代 to 區的對象在經過多次 GC 後,如果還沒有死亡,則認為他是一個老對象,則可以晉升到老年代,而這個年齡(GC 次數)是可以設置的,有就是這個參數。默認值時15。超過15 則認為是無限大(因為age變量時4個 bit,超過15無法表達)。但該參數不是唯一決定對象晉升的條件。當 to 區不夠或者改對象年齡已經達到了平均晉升值或者大對象等等條件。

  5. -XX:TargetSurvivorRatio={value} 決定對何時晉升的不僅只有 XX:MaxTenuringThreshold 參數,如果在 Survivor 空間中相同年齡所有對象大小的總和大魚 Survivor 空間的一半(默認50%),年齡大於或等於該年齡的對象就可以直接進入老年代。無需在乎 XX:MaxTenuringThreshold參數。因此,MaxTenuringThreshold 只是對象晉升的最大年齡。如果將 TargetSurvivorRatio 設置的很小,對象將晉升的很快。

  6. -XX:PretenureSizeThresholds={value} 除了年齡外,對象的體積也是影響晉升的一個關鍵,也就是大對象。如果一個對象新生代放不下,只能直接通過分配擔保機制進入老年代。該參數是設置對象直接晉升到老年代的閾值,單位是字節。只要對象的大小大於此閾值,就會直接繞過新生代,直接進入老年代。註意:這個參數只對 Serial 和 ParNew 有效,ParallelGC 無效,默認情況下該值為0,也就是不指定最大的晉升大小,一切有運行情況決定。

  7. -XX:-UseTLAB 禁用線程本地分配緩存。TLAB 的全稱是 Thread LocalAllocation Buffer ,即線程本地線程分配緩存,是一個線程私有的內存區域。該設計是為了加速對象分配速度。由於對象一般都是分配在堆上,而對是線程共享的。因此肯定有鎖,雖然使用 CAS 的操作,但性能仍有優化空間。通過為每一個線程分配一個 TLAB 的空間(在 eden 區),可以消除多個線程同步的開銷。默認開啟。

  8. -XX:TLABSize 指定 TLAB 的大小。

  9. -XX:+PrintTLAB 跟蹤 TLAB 的使用情況。用以確定是用多大的 TLABSize。

  10. -XX:+ResizeTLAB 自動調整 TLAB 大小。

同時,對象也可能會在棧上分配,棧上分配,TLAB 分配,堆分配,他們的流程如下:

技術分享圖片

還有一些開啟 GC 日誌的參數,是 GC 調優不可或缺的工具。

  1. -XX:+PrintGCDateStamps 打印 GC 日誌時間戳。

  2. -XX:+PrintGCDetails 打印 GC 詳情。

  3. -XX:+PrintGCTimeStamps: 打印此次垃圾回收距離jvm開始運行的所耗時間。

  4. -Xloggc: 將垃圾回收信息輸出到指定文件

  5. -verbose:gc 打印 GC 日誌

  6. -XX:+PrintGCApplicationStopedTime 查看 gc 造成的應用暫停時間

  7. XX:+PrintTenuringDistribution, 對象晉升的日誌

  8. -XX:+HeapDumpOnOutOfMemoryError 內存溢出時輸出 dump 文件。

# 總結

好了,我們已經將一些常用的 GC 參數介紹了,當然會有遺漏的,如有遺漏或者介紹有誤的,請告知本人。這些參數不僅僅是為了服務大家,同時也是自己做的一個總結,以後就不用到處找了。說白了這就是寫博客的好處:總結了自己,也做了備份,同時也可能幫助了別人。

Good Luck!!!

深入淺出 JVM GC(4)常用 GC 參數介紹