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
垃圾收集器搭配
只有有連線就可以搭配使用,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垃圾收集過程
- CMS initial mark :初始標(biāo)記Root,STW
- CMS Concurrent mark: 并發(fā)標(biāo)記
- CMS-concurrent-preclean: 并發(fā)預(yù)清理
- CMS remark: 重新標(biāo)記,STW
- CMS concurrent-sweep:并發(fā)清除
- 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
- Initial marking phase: 標(biāo)記GC Root,STW
- Root region scanning phase: 標(biāo)記存活Region
- Concurrent marking phase: 標(biāo)記存活的對象
- Remark phase: 重新標(biāo)記坏挠,STW
- 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日志工具
- 在線工具:http://gceasy.io/
- 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/gc.log
Parallel GC調(diào)優(yōu)的指導(dǎo)原則
- 除非確定递递,否則不要設(shè)置最大堆內(nèi)存
- 優(yōu)先設(shè)置吞吐量目標(biāo)
- 如果吞吐量目標(biāo)達(dá)不到忿族,調(diào)大最大內(nèi)存,不能讓OS使用Swap驻啤,如果仍然達(dá)不到菲驴,降低目標(biāo)。
- 吞吐量能達(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