5.JVM層GC調(diào)優(yōu)

JVM與調(diào)優(yōu) imooc JVM Markdown

JVM的內(nèi)存結(jié)構(gòu)

運(yùn)行時(shí)數(shù)據(jù)區(qū)

方法區(qū)          (共享)
堆              (共享)
虛擬機(jī)棧         (私有)
本地方法棧       (私有)
程序計(jì)數(shù)器(PC)  (私有)

程序計(jì)數(shù)器PC Register
JVM支持多線程同時(shí)運(yùn)行,每個(gè)線程有自己的PC Register,線程正在執(zhí)行的方法叫做當(dāng)前方法练链,如果是java代碼,PC Register里面存放的就是當(dāng)前正在執(zhí)行的指令的地址扇住。如果是C代碼茵乱,則為空。

虛擬機(jī)棧JVM Stacks
Java虛擬機(jī)棧(Java Virtual Machine Stacks) 是線程私有的威根,生命周期與線程相同。虛擬機(jī)棧描述的是Java方法執(zhí)行的內(nèi)存模型:每個(gè)方法在執(zhí)行的同時(shí)都會創(chuàng)建一個(gè)棧幀视乐,用于存儲局部變量表洛搀、操作數(shù)棧動態(tài)鏈接佑淀、方法出口等信息留美。每一個(gè)方法從調(diào)用直至執(zhí)行完成的過程,就對應(yīng)著一個(gè)棧幀在虛擬機(jī)棧中入棧到出棧的過程。

堆Heap
Java堆是Java虛擬機(jī)所管理的內(nèi)存中最大的一塊谎砾。堆是被所有線程共享的一塊內(nèi)存區(qū)域逢倍,在虛擬機(jī)啟動時(shí)創(chuàng)建。此內(nèi)存區(qū)域的唯一目的就是存放對象示例景图,幾乎所有的對象實(shí)例都在這里分配內(nèi)存较雕。
Java堆可以處于物理上不連續(xù)的內(nèi)存空間中,只要邏輯上是連續(xù)的即可症歇。
堆的優(yōu)勢是可以在運(yùn)行時(shí)動態(tài)地分配內(nèi)存空間郎笆,不必事先告訴編譯器。

方法區(qū)Method Area
方法區(qū)與Java堆一樣忘晤,是各個(gè)線程共享的內(nèi)存區(qū)域宛蚓,它用于存儲已被虛擬機(jī)加載的類信息、常量设塔、靜態(tài)變量凄吏、即時(shí)編譯器編譯后的代碼等數(shù)據(jù)。雖然Java虛擬機(jī)規(guī)范把方法區(qū)描述為堆的一個(gè)邏輯部分闰蛔,但是它卻有一個(gè)別名叫做Non-Heap(非堆)痕钢,目的是與Java堆區(qū)分開來。對應(yīng)于jdk1.8 的MetaSpace序六。

tips: 常量池Run-Time Constant Pool
運(yùn)行時(shí)常量池(Runtime Constant Pool)是方法區(qū)的一部分任连。Class文件中除了有類的版本、字段例诀、方法随抠、接口等描述信息外,還有一項(xiàng)信息是常量池(Constant Pool Table)繁涂,用于存放編譯器生成的各種字面量和符號引用拱她,這部分內(nèi)容將在類加載后進(jìn)入方法區(qū)的運(yùn)行時(shí)常量池中存放。

本地方法棧Native Method Stacks
本地方法棧(Native Method Stack)與虛擬機(jī)棧所發(fā)揮的作用是非常相似的扔罪,它們之間的區(qū)別不過是虛擬機(jī)棧為虛擬機(jī)執(zhí)行Java方法(也就是字節(jié)碼)服務(wù)秉沼,而本地方法棧則為虛擬機(jī)使用到的Native方法服務(wù)

非堆區(qū): 是操作系統(tǒng)的本地內(nèi)存矿酵,獨(dú)立于JVM之外的
Metaspace= Class唬复、Package、Method坏瘩、Field盅抚、字節(jié)碼、常量池倔矾、符號引用等等
CCS: 32位指針的Class
CodeCache: JIT編譯后的本地代碼、JNI使用的C代碼

常用參數(shù)

-Xms  -Xmx
-XX:NewSize -XX:MaxNewSize (新生代的大小/最大的大小)
-XX:NewRatio(New區(qū)和Old區(qū)比例) -XX:SurvivorRatio (Eden區(qū)和Survivor區(qū)比例)
-XX:MetaspaceSize -XX:MaxMetaspaceSize (指定Metaspace大小)    
-XX:+UseCompressedClassPointers(是否啟用壓縮的類指針)
-XX:CompressedClassSpaceSize(設(shè)置壓縮類指針的內(nèi)存大小,默認(rèn)1G)
-XX:InitialCodeCacheSize    
-XX:ReservedCodeCacheSize

常用垃圾回收算法

思想:枚舉根節(jié)點(diǎn)哪自,做可達(dá)性分析
根節(jié)點(diǎn):類加載器丰包、Thread、虛擬機(jī)棧的本地變量表壤巷、static成員邑彪、常量引用、本地方法棧的變量等等胧华。

標(biāo)記清除算法

  • 算法思想
    算法分為”標(biāo)記“和”清除”兩個(gè)階段:首先標(biāo)記出所有需要回收的對象寄症,在標(biāo)記完成后統(tǒng)一回收所有。
  • 缺點(diǎn)
    效率不高矩动。標(biāo)記和清除兩個(gè)過程效率都不高有巧。容易產(chǎn)生碎片(可能不連續(xù)),碎片太多會導(dǎo)致提前GC悲没。

復(fù)制

  • 算法思想
    它將可用內(nèi)存按容量劃分位大小相等的兩塊篮迎,每次只使用其中的一塊。當(dāng)這一塊的內(nèi)存用完了示姿,就將還存活著的對象復(fù)制到另外一塊上面甜橱,然后再把已使用過的內(nèi)存空間一次清理掉。(Survivor1 和Survivor2就是采用復(fù)制算法
  • 優(yōu)缺點(diǎn)
    實(shí)現(xiàn)簡單栈戳,運(yùn)行搞笑岂傲,但是空間利用率低。

標(biāo)記整理

  • 算法思想
    標(biāo)記過程仍然與“標(biāo)記-清除” 算法一樣子檀,但后續(xù)步驟不是直接對可回收對象進(jìn)行清理镊掖,而是讓所有存活的對象都向一端移動,然后直接清理掉端邊界以外的內(nèi)存命锄。
  • 優(yōu)缺點(diǎn)
    沒有了內(nèi)存碎片堰乔。但是整理內(nèi)存比較耗時(shí)。

分代垃圾回收

Young區(qū)用復(fù)制算法
Old區(qū)用標(biāo)記清除或者標(biāo)記整理

對象分配

對象優(yōu)先在Eden區(qū)分配
大對象直接進(jìn)入老年代:-XX:PretenureSizeThreshold (通過這個(gè)參數(shù))脐恩,超過這個(gè)參數(shù)的值镐侯,進(jìn)入老年代
長期存活對象進(jìn)入老年代:-XX:MaxTenuringThreshold -XX:+PrintTenuringDistribution -XX:TargetSuivivorRatio

垃圾收集器

串行收集器Serial:Serial、Serial Old
并行收集器Parallel:Parallel Scavenge驶冒、Parallel Old苟翻、(吞吐量優(yōu)先)    
并發(fā)收集器Concurrent:CMS、G1骗污、(停頓時(shí)間優(yōu)先)

tips: 并行 vs 并發(fā)

并行(Parallel):指多條垃圾收集線程并行工作崇猫,但此時(shí)用戶線程仍然處于等待狀態(tài)。適合科學(xué)計(jì)算需忿、后臺處理等弱交互場景诅炉。
并發(fā)(Concurrent):指用戶線程與垃圾收集線程同時(shí)執(zhí)行(但不一定是并行的蜡歹,可能會交替執(zhí)行),垃圾收集線程在執(zhí)行的時(shí)候不會停頓用戶程序的運(yùn)行涕烧。適合對響應(yīng)時(shí)間有要求的場景月而,比如Web。

tips: 停頓時(shí)間 vs 吞吐量

停頓時(shí)間:垃圾收集器做垃圾回收中斷應(yīng)用執(zhí)行的時(shí)間议纯。-XX:MaxGCPauseMillis
吞吐量:花在垃圾收集的時(shí)間和花在應(yīng)用時(shí)間的占比父款。-XX:GCTimeRatio=<n>,垃圾收集時(shí)間占比:1/1+n瞻凤。

串行收集器

-XX:+UseSerialGC
-XX:+UseSerialOldGC

并行收集器

吞吐量優(yōu)先
-XX:+UseParallelGC憨攒、-XX:+UseParallelOldGC
Server模式下的默認(rèn)收集器(總共client、server兩種阀参,默認(rèn)超過2G肝集,會啟動Server)

并發(fā)收集器

響應(yīng)時(shí)間優(yōu)先
CMS:-XX:+UseConcMarkSweepGC (old區(qū)方式) -XX:+UseParNewGC (young區(qū)方式)
G1: -XX:+UseG1GC

垃圾收集器搭配

image.png

只有有連線就可以搭配使用,java8推薦使用G1(Young區(qū)结笨、Old區(qū)都可以使用)

如何選擇垃圾收集器

  • 優(yōu)先調(diào)整堆的大小讓服務(wù)器自己來選擇
  • 如果內(nèi)存小于100M包晰,使用串行收集器
  • 如果是單核,并且沒有停頓時(shí)間的要求炕吸,串行或者JVM自己選
  • 如果允許停頓時(shí)間超過1秒伐憾,選擇并行或者JVM自己選
  • 如果響應(yīng)時(shí)間最重要,并且不能超過1秒赫模,使用并發(fā)收集器

Parallel Collector

-XX:+UseParallelGC 手動開啟树肃,Server默認(rèn)開啟
-XX:ParallelGCThreads=<N> 多少個(gè)GC線程
CPU > 8 N = 5 / 8
CPU < 8N = CPU

Parallel Collector Ergonomics(自適應(yīng))

-XX:MaxGCPauseMillis=<N>
-XX:GCTimeRatio=<N>
-Xmx<N>
Ergonomics 方式需要動態(tài)調(diào)整每個(gè)區(qū)的條件,性能不是最好瀑罗。

動態(tài)內(nèi)存調(diào)整

-XX:YoungGenerationSizeIncrement=<Y> 默認(rèn)20%
-XX:TenuredGenerationSizeIncrement=<T> 默認(rèn)20%
-XX:AdaptiveSizeDecrementScaleFactor=<D> 默認(rèn)4%
使用比較少胸嘴。

CMS Collector

  • 并發(fā)收集
  • 低停頓 低延遲
  • 老年代收集器

CMS垃圾收集過程

  1. CMS initial mark :初始標(biāo)記Root,STW
  2. CMS Concurrent mark: 并發(fā)標(biāo)記
  3. CMS-concurrent-preclean: 并發(fā)預(yù)清理
  4. CMS remark: 重新標(biāo)記,STW
  5. CMS concurrent-sweep:并發(fā)清除
  6. CMS-concurrent-reset:并發(fā)重置

CMS的缺點(diǎn)

CPU敏感(GC與應(yīng)用一起使用)
浮動垃圾
空間碎片

CMS的相關(guān)參數(shù)

-XX:ConcGCThreads: 并發(fā)的GC線程數(shù)
-XX:+UseCMSCompactAtFullCollection: FullGC之后做壓縮
-XX:CMSFullGCsBeforeCompaction: 多少次FullGC之后壓縮一次
-XX:CMSInitiatingOccupancyFraction: 觸發(fā)FullGC (默認(rèn)92%old區(qū)垃圾)
-XX:+UseCMSInitiatingOccupancyOnly:是否動態(tài)調(diào)
-XX:+CMSScavengeBeforeRemark: FullGC之前先做YGC(調(diào)優(yōu)參數(shù)斩祭,通常會打開)
-XX:+CMSClassUnloadingEnabled: 啟用回收Perm區(qū)(1.7之前)

iCMS (增量的CMS)

適用于單核或雙核(1.8已經(jīng)廢棄)

G1 Collector (1.8主流劣像、1.9默認(rèn),并將CMS過時(shí))

The Garbage-First (G1) collector is a server-style garbage collector, targeted for multi-processor machines with large memories. It meets garbage collection (GC) pause time goals with a high probability, while achieving high throughput. The G1 garbage collector is fully supported in Oracle JDK 7 update 4 and later releases. This means heap sizes of around 6GB or larger,and a stable and predictable pause time below 0.5 seconds.

新生代和老生代收集器

G1的幾個(gè)概念

Region
SATB: Snapshot-At-The-Begining,它是通過Root Tracing得到的摧玫,GC開始時(shí)候存活對象的快照耳奕。
RSet:記錄了其他Region中的對象引用本Region中對象的關(guān)系,屬于points-into結(jié)構(gòu)(誰引用了我的對象)

YoungGC

新對象進(jìn)入Eden區(qū)
存活對象拷貝到Survivor區(qū)
存活時(shí)間達(dá)到年齡閾值時(shí)诬像,對象晉升到Old區(qū)
以上 階段和通常的GC收集器一致

MixedGC

不是FullGC屋群,回收所有的Young和部分Old
global concurrent marking

global concurrent marking

  1. Initial marking phase: 標(biāo)記GC Root,STW
  2. Root region scanning phase: 標(biāo)記存活Region
  3. Concurrent marking phase: 標(biāo)記存活的對象
  4. Remark phase: 重新標(biāo)記坏挠,STW
  5. Cleanup phase:部分STW

MixedGC時(shí)機(jī)

  • InitiatingHeapOccupancyPercent:
    堆占用率達(dá)到這個(gè)數(shù)值則觸發(fā)global concurrent marking芍躏,默認(rèn)45%

  • G1HeapWastePercent:
    在global concurrent marking結(jié)束之后,可以知道區(qū)有多少空間要被回收降狠,在每次YGC之后和再次發(fā)生Mixed GC之前对竣,會檢查垃圾占比是否達(dá)到此參數(shù)庇楞,只有達(dá)到了,下次才會發(fā)生Mixed GC柏肪。

MixedGC相關(guān)參數(shù)

G1MixedGCLiveThresholdPercent:Old區(qū)的region被回收時(shí)候的存活對象占比
G1MixedGCCountTarget:一次global concurrent marking之后姐刁,最多執(zhí)行Mixed GC的次數(shù)芥牌。
G1OldCSetRegionThreshodPercent:一次Mixed GC中能被選入CSet的最多old區(qū)的region數(shù)量
-XX:+UseG1GC: 開啟G1
-XX:G1HeapRegionSize=n: region的大小烦味,1-32M,2048個(gè)
-XX:MaxGCPauseMillis=200:最大停頓時(shí)間
-XX:G1NewSizePervent壁拉、-XX:G1MaxNewSizePercent
-XX:G1ReservePercent=10: 保留防止to space溢出
-XX:ParallelGCThreads=n: STW線程數(shù)
-XX:ConcGCThreads=n:并發(fā)線程數(shù)=1/4*并行

G1最佳實(shí)踐

  • 年輕代大忻怼: 避免使用-Xmn、-XX:NewRatio等顯式設(shè)置Young區(qū)大小弃理,會覆蓋暫停時(shí)間目標(biāo)溃论。
  • 暫停時(shí)間目標(biāo):暫停時(shí)間不要太嚴(yán)苛,其吞吐量目標(biāo)是90%的應(yīng)用程序時(shí)間和10%的垃圾回收時(shí)間痘昌,太嚴(yán)苛?xí)苯佑绊懙酵掏铝俊?/li>
  • 關(guān)于MixedGC調(diào)優(yōu):
    -XX:InitiatingHeapOccupancyPercent
    -XX:G1MixedGCLiveThresholdPercent、-XX:G1HeapWastePercent
    -XX:G1MixedGCCountTarget
    -XX:G1OldCSetRegionThresholdPercent

切換到G1的場景

50%以上的堆被存活對象占用
對象分配和晉升的速度變化非常大
垃圾回收時(shí)間特別長,超過了1秒

可視化GC日志工具

  1. 在線工具:http://gceasy.io/
  2. GCViewer

打印日志相關(guān)參數(shù)

-XX:+PrintGCDetails -XX:+PrintGCTimeStamps
-XX:+PrintGCDateStamps
-Xloggc:$CATALINA_HOME/logs/gc.log
-XX:+PrintHeapAtGC
-XX:+PrintTenuringDistribution

ParallelGC調(diào)優(yōu)

初始設(shè)置

-XX:+DisableExplicitGC (禁用明確GC)
-XX:+HeapDumpOnOutOfMemoryError
-XX:+HeapDumpPath=CATALINA_HOME/logs/ -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDataStamps -Xloggc:CATALINA_HOME/logs/gc.log

Parallel GC調(diào)優(yōu)的指導(dǎo)原則

  1. 除非確定递递,否則不要設(shè)置最大堆內(nèi)存
  2. 優(yōu)先設(shè)置吞吐量目標(biāo)
  3. 如果吞吐量目標(biāo)達(dá)不到忿族,調(diào)大最大內(nèi)存,不能讓OS使用Swap驻啤,如果仍然達(dá)不到菲驴,降低目標(biāo)。
  4. 吞吐量能達(dá)到骑冗,GC時(shí)間太長赊瞬,設(shè)置停頓時(shí)間的目標(biāo)。

ParallelGC調(diào)優(yōu)(參考)

  • 設(shè)置Metaspace大小
    -XX:MetaspaceSize=64M -XX:MaxMetaspaceSize=64M

  • 添加吞吐量和停頓時(shí)間參數(shù)
    -XX:GCTimeRatio=99 -XX:MaxGCPauseMillis=100

  • 修改動態(tài)擴(kuò)容增量
    -XX:YoungGenerationSizeIncrement=30

G1 GC調(diào)優(yōu)

G1調(diào)優(yōu)相關(guān)參數(shù)

-XX:+UseG1GC
-Xms128M
-Xmx128M
-XX:MetaspaceSize=64M
-XX:MaxGCPauseMillis=100
-XX:+UseStringDeduplication
-XX:StringDeduplicationAgeThreshold=3

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末贼涩,一起剝皮案震驚了整個(gè)濱河市巧涧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌遥倦,老刑警劉巖谤绳,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異谊迄,居然都是意外死亡闷供,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門统诺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來歪脏,“玉大人,你說我怎么就攤上這事粮呢⌒鍪В” “怎么了钞艇?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長豪硅。 經(jīng)常有香客問我哩照,道長,這世上最難降的妖魔是什么懒浮? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任飘弧,我火速辦了婚禮,結(jié)果婚禮上砚著,老公的妹妹穿的比我還像新娘次伶。我一直安慰自己,他們只是感情好稽穆,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布冠王。 她就那樣靜靜地躺著,像睡著了一般舌镶。 火紅的嫁衣襯著肌膚如雪柱彻。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天餐胀,我揣著相機(jī)與錄音哟楷,去河邊找鬼。 笑死骂澄,一個(gè)胖子當(dāng)著我的面吹牛吓蘑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播坟冲,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼磨镶,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了健提?” 一聲冷哼從身側(cè)響起琳猫,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎私痹,沒想到半個(gè)月后脐嫂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡紊遵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年账千,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片暗膜。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡匀奏,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出学搜,到底是詐尸還是另有隱情娃善,我是刑警寧澤论衍,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站聚磺,受9級特大地震影響坯台,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜瘫寝,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一蜒蕾、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧矢沿,春花似錦滥搭、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽闽坡。三九已至栽惶,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間疾嗅,已是汗流浹背外厂。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留代承,地道東北人汁蝶。 一個(gè)月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像论悴,于是被迫代替她去往敵國和親掖棉。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容