排查思路及常用命令
1矾睦、查看java進(jìn)程
ps -ef | grep java
jps
2税娜、檢查JVM配置
ps aux | grep "applicationName=adsearch"
3北救、查看堆內(nèi)存情況
jmap -heap 進(jìn)程ID | head -n20
4兑凿、觀察老年代的內(nèi)存使用情況剩蟀,推測(cè)可能原因
GC后的短時(shí)間能夠恢復(fù)到一定值,即可排除是內(nèi)存泄露
5荔仁、jmap查看堆內(nèi)存中的對(duì)象信息
jmap -histo 進(jìn)程ID | head -n20
6、dump堆內(nèi)存文件
jmap -dump:format=b,file=heap 進(jìn)程ID
7芽死、用分析工具分析dump文件
jhat乏梁、JVisualVM
找到大對(duì)象
8、最后通過(guò)代碼分析可疑對(duì)象
.
GC會(huì)對(duì)程序產(chǎn)生影響
FGC過(guò)于頻繁:導(dǎo)致工作線程頻繁被停止关贵,讓系統(tǒng)看起來(lái)一直有卡頓現(xiàn)象掌呜,也會(huì)使得程序的整體性能變差
YGC耗時(shí)過(guò)長(zhǎng):卡頓時(shí)間就會(huì)增大,加上YGC本身比較頻繁坪哄,就會(huì)導(dǎo)致比較多的服務(wù)超時(shí)問(wèn)題
FGC耗時(shí)過(guò)長(zhǎng):卡頓時(shí)間增加质蕉,尤其對(duì)于高并發(fā)服務(wù)势篡,可能導(dǎo)致FGC期間比較多的超時(shí)問(wèn)題,可用性降低
YGC過(guò)于頻繁:降低服務(wù)的整體性能
.
導(dǎo)致FGC的原因
大對(duì)象:系統(tǒng)一次性加載了過(guò)多數(shù)據(jù)到內(nèi)存中(比如SQL查詢未做分頁(yè))模暗,導(dǎo)致大對(duì)象進(jìn)入了老年代禁悠。
內(nèi)存泄漏:頻繁創(chuàng)建了大量對(duì)象,但是無(wú)法被回收(比如IO對(duì)象使用完后未調(diào)用close方法釋放資源)兑宇,先引發(fā)FGC碍侦,最后導(dǎo)致OOM。
程序頻繁生成一些長(zhǎng)生命周期的對(duì)象隶糕,當(dāng)這些對(duì)象的存活年齡超過(guò)分代年齡時(shí)便會(huì)進(jìn)入老年代瓷产,最后引發(fā)FGC. (即本文中的案例)。
程序BUG導(dǎo)致動(dòng)態(tài)生成了很多新類枚驻,使得 Metaspace 不斷被占用濒旦,先引發(fā)FGC,最后導(dǎo)致OOM再登。
代碼中顯式調(diào)用了gc方法尔邓,包括自己的代碼甚至框架中的代碼。
JVM參數(shù)設(shè)置問(wèn)題:包括總內(nèi)存大小锉矢、新生代和老年代的大小梯嗽、Eden區(qū)和S區(qū)的大小、元空間大小沽损、垃圾回收算法等等灯节。
寫(xiě)完mybatis的SQL之后,一定要對(duì)各種 <if test> 進(jìn)行空值考慮绵估,我公司一次FGC就是因?yàn)檫@個(gè)導(dǎo)致的显晶,另外部門(mén)定時(shí)推送過(guò)來(lái)的訂單refId存在為空的情況,導(dǎo)致select的時(shí)候掃描全表幾千萬(wàn)條數(shù)據(jù)(還是分庫(kù)分表的壹士。磷雇。。)躏救,導(dǎo)致產(chǎn)生了很多實(shí)體類對(duì)象和mybatis緩存對(duì)象唯笙。
所以對(duì)于只有查詢一行的SQL語(yǔ)句,要加上limit 1盒使,防止 <if test> 條件為空而導(dǎo)致掃描全表數(shù)據(jù)
.
排查總結(jié)
查看監(jiān)控崩掘,記錄出現(xiàn)問(wèn)題的時(shí)間點(diǎn)和FGC頻率
了解該時(shí)間點(diǎn)有沒(méi)有上線版本
查看JVM參數(shù)設(shè)置:堆空間各個(gè)區(qū)域的大小,采用哪些垃圾回收器少办,分析JVM參數(shù)是否合理
對(duì)可能的原因進(jìn)行排除:元空間打滿苞慢、內(nèi)存泄露、代碼顯示調(diào)用gc
通過(guò) jmap -histo 命令并結(jié)合dump堆內(nèi)存文件作進(jìn)一步分析是否存在大對(duì)象或者長(zhǎng)生命周期的對(duì)象
通過(guò)可疑對(duì)象英妓,定位到具體代碼