生產(chǎn)環(huán)境 OOM 與 GC 問題的處理思路
數(shù)據(jù)庫(kù)排名:MySQL跳出“同期跌幅榜”,拿下“漲幅榜冠軍”
有一定 Java 工作經(jīng)驗(yàn)的朋友們,免不了要遇到過,或者處理過 OOM 和 GC 問題。OOM 和 GC 問題也是面試時(shí),經(jīng)常被面試官問題的問題。分享一下多年積累的一些小經(jīng)驗(yàn),共同進(jìn)步。
0x01:未雨綢繆
部署到生產(chǎn)環(huán)境的應(yīng)用,無(wú)論是 C/S 結(jié)構(gòu),還是 B/S 結(jié)構(gòu)的應(yīng)用服務(wù)。肯定有基于 Shell 腳本編寫的啟動(dòng)腳本。C/S 結(jié)構(gòu)的應(yīng)用服務(wù)的 Shell 腳本一般是公司內(nèi)部開發(fā)人員編寫的;以下一個(gè) C/S 結(jié)構(gòu)應(yīng)用服務(wù)的簡(jiǎn)單啟動(dòng)腳本。
java -Xms1024m -Xmx1024m -XX:PermSize=256m \
-XX:MaxPermSize=512m -XX:-HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=./ -XX:+PrintGCDetails -Xloggc:./gc.log -jar \
plugins/org.eclipse.equinox.launcher_1.0.201.R35x_v20090715.jar -clean -refresh &
而 B/S 結(jié)構(gòu)的一般是應(yīng)用服務(wù)器的啟動(dòng) Shell 腳本。例如,應(yīng)用服務(wù)器 Apache Tomcat bin 目錄下的 startup.sh。

而 Apache Tomcat 的啟動(dòng) Shell 腳本并沒有配置發(fā)生 OOM 時(shí),打印 JVM 內(nèi)存快照的JVM參數(shù)和打印 GC 日志的JVM參數(shù)。所以生成環(huán)境的 Tomcat 服務(wù)一般需要進(jìn)行 JVM 參數(shù)優(yōu)化。
怎么對(duì)線上的 OOM 和 GC 問題進(jìn)行未雨綢繆呢?那就是認(rèn)為自己部署的任何服務(wù)都是會(huì)發(fā)生 OOM 和 GC 問題的。在啟動(dòng)腳本里加上相應(yīng)的參數(shù),防止真的出現(xiàn) OOM 和 GC 問題時(shí),無(wú)證可查。
打印 OOM 快照配置:
-XX:-HeapDumpOnOutOfMemoryError :當(dāng)堆內(nèi)存空間溢出時(shí)輸出堆的內(nèi)存快照
-XX:HeapDumpPath :指定輸入的目錄
也就是說(shuō)當(dāng)發(fā)生 OutOfMemoryError 錯(cuò)誤時(shí),才能觸發(fā) -XX:HeapDumpOnOutOfMemoryError 輸出到 -XX:HeapDumpPath 指定的目錄。
打印 GC 日志:
-XX:+PrintGCDetails:打印 GC 日志詳細(xì)信息
-Xloggc:GC 日志輸入的目錄

0x02:線上分析
有時(shí)并不一定是要宕機(jī)了才去分析 OOM 和 GC 問題。目前大型的系統(tǒng)服務(wù)都是配備了監(jiān)控系統(tǒng),一旦發(fā)現(xiàn)服務(wù)處于不健康運(yùn)行的狀態(tài),就會(huì)觸發(fā)預(yù)警。給運(yùn)維人員發(fā)送郵件、短信等,這時(shí)就可以對(duì)觸發(fā)預(yù)警的服務(wù)進(jìn)行問題分析了。這時(shí)對(duì)這些正在提供生成服務(wù)的應(yīng)用服務(wù)進(jìn)行分析就需要額外小心,稍不留神就造成更嚴(yán)重的生產(chǎn)事故,給公司帶來(lái)嚴(yán)重的損失,同時(shí)也給自己的考核帶來(lái)不利影響。
對(duì)于向上分析一般使用 JDK 提供的各種運(yùn)維工具,找到問題的所在。
監(jiān)視工具:jps、jstat、jstatd、jmc
故障排除工具:jcmd、jinfo、jhat、jmap、jsadebugd、jstack
官網(wǎng):https://docs.oracle.com/javase/8/docs/technotes/tools/unix/
jps (JavaVirtual Machine Process Status Tool): 虛擬機(jī)進(jìn)程狀況工具
命令格式:jps [options] [hostid]
-q : 抑制類名的輸出,JAR文件名和傳遞給main方法的參數(shù),僅生成本地JVM標(biāo)識(shí)符列表。
-m: 顯示傳遞給該main方法的參數(shù)。輸出可能是null嵌入式JVM。
-l : 顯示應(yīng)用程序main類的完整包名或應(yīng)用程序的JAR文件的完整路徑名。
-v : 顯示傳遞給JVM的參數(shù)。
-V : 抑制類名的輸出,JAR文件名和傳遞給main方法的參數(shù),僅生成本地JVM標(biāo)識(shí)符的列表。
-Joption : 傳遞option給JVM,其中的選項(xiàng)是optionsJava應(yīng)用程序啟動(dòng)器的參考頁(yè)面中描述的選項(xiàng)之一。
例如,-J-Xms48m將啟動(dòng)內(nèi)存設(shè)置為48 MB。
jstat (Java Virtual Machine (JVM) statistics):監(jiān)視Java虛擬機(jī)(JVM)統(tǒng)計(jì)信息
命令格式:jstat [ option vmid [interval[s|ms] [count] ]
Interval: 間隔時(shí)間 count:次數(shù)
class:顯示類加載器行為的統(tǒng)計(jì)信息。
compiler:顯示有關(guān)Java HotSpot VM即時(shí)編譯器行為的統(tǒng)計(jì)信息。
gc:顯示垃圾回收堆行為的統(tǒng)計(jì)信息。
gccapacity:顯示有關(guān)世代及其對(duì)應(yīng)空間容量的統(tǒng)計(jì)數(shù)據(jù)。
gccause:顯示有關(guān)垃圾回收統(tǒng)計(jì)信息(相同-gcutil)的摘要,其中包含最后和當(dāng)前(適用時(shí))垃圾收集事件的原因。
gcnew:顯示新一代行為的統(tǒng)計(jì)信息。
gcnewcapacity:顯示有關(guān)新一代及其相應(yīng)空間大小的統(tǒng)計(jì)信息。
gcold:顯示舊版本和Metaspace統(tǒng)計(jì)信息的統(tǒng)計(jì)信息。
gcoldcapacity:顯示有關(guān)舊一代大小的統(tǒng)計(jì)信息。
gcmetacapacity:顯示有關(guān)元空間大小的統(tǒng)計(jì)信息。
gcutil:顯示有關(guān)垃圾收集統(tǒng)計(jì)信息的摘要。
printcompilation:顯示Java HotSpot VM編譯方法統(tǒng)計(jì)信息。
jinfo (Configuration Info for Java):生成配置信息
命令格式:jinfo [ option ] pid
-flag 名稱 : 打印指定命令行標(biāo)志的名稱和值。
-flag [+ | - ]名稱 : 啟用或禁用指定的布爾命令行標(biāo)志。
-flag name = value : 將指定的命令行標(biāo)志設(shè)置為指定的值。
-flags : 打印傳遞給JVM的命令行標(biāo)志。
-sysprops : 將Java系統(tǒng)屬性打印為名。
jmap (Memory Map for Java):內(nèi)存映射工具 [ 生成堆轉(zhuǎn)儲(chǔ)快照 ]
命令格式:jinfo [ option ] vmid
-dump:[live,] format = b,file = filename :以hprof二進(jìn)制格式轉(zhuǎn)儲(chǔ)Java堆filename。live子選項(xiàng)說(shuō)明是否之dump出存活的對(duì)象。
-finalizerinfo : 打印有關(guān)正在等待最終確定的對(duì)象的信息(linux)。
-heap :顯示java堆詳細(xì)信息,如使用哪種回收器、參數(shù)配置、分代狀況等(linux)。
-histo [:live] : 顯示堆中對(duì)象統(tǒng)計(jì)信息,包括類、實(shí)例數(shù)量、合計(jì)容量。
-clstats : 打印Java堆的類加載器智能統(tǒng)計(jì)。對(duì)于每個(gè)類加載器,它的名稱,它的活動(dòng)程度,地址,父類加載器以及它加載的類的數(shù)量和大小。
-F : -dump或 -histo選項(xiàng)不響應(yīng)時(shí),該選項(xiàng)強(qiáng)制生成dump快照(不支持live)。
jhat (JVM Heap Analysis Tool):虛擬機(jī)堆轉(zhuǎn)儲(chǔ)快照分析工具
命令格式:jhat [ options ] 堆轉(zhuǎn)儲(chǔ)文件
jstack (Stack Trace for Java):Java堆棧跟蹤工具
命令格式:jstack [ options ] pid
-F : jstack[ -l] pid不響應(yīng)時(shí)強(qiáng)制堆棧轉(zhuǎn)儲(chǔ)。
-l : 打印有關(guān)鎖的其他信息,例如,java.util.concurrent 所擁有的同步器列表。
-m : 打印混合模式堆棧跟蹤,其中包含 Java 和本機(jī) C/C ++ 框架。
這么多監(jiān)視工具和故障排除工具中,常用的是 jps、jstat、jstack 和 jmap
0x03:線下分析
通過未雨綢繆和線上分析還沒法肉眼看出一些問題的端倪來(lái)的話,為了不影響生產(chǎn)。就需要把這兩步收集的 JVM 內(nèi)存快照,拿到線下來(lái)分析。JDK 和一些第三方工具,提供了非常好用的可視化工具來(lái)分析JVM 內(nèi)存快照。主要有 JDK 提供的 jconsole、VisualVM;第三方提供的有Eclipse Memory Analyzer(免費(fèi))、JProfiler(商業(yè))。常用可以化工具可以參考該文章 [ Java進(jìn)行內(nèi)存泄露 GC 分析都有哪些常用好用的工具 ]

喜歡,在看
