Spring Boot —— 如何排查內存溢出問題

Spring Boot —— 如何排查內存溢出問題

前言

總結看到的博客,記錄下,有備無患。

場景一

Spring Boot 項目JVM啓動配置爲 -Xms4g -Xmx4g,程序運行一段時間內存越來越高,最終超過了可承受的內存容量,只能臨時重啓服務,達到應用有效。

思考

常用排查命令

jstat -class PID

jstat -compiler PID

jstat -gc PID

jstat -gccapacity PID

jstat -gcutil PID

查看堆比例

jstat -gccause PID

jstat -gcnew PID

jstat -gcnewcapacity PID

jstat -gcold PID

jstat -gcoldcapcacity PID

jstat -printcompilation PID

jmap -histo PID

查看類的實例

jmap -heap PID

查看堆棧信息

jmap -dump:live,format=b,file=/tmp/m.hprof PID

保存內存的堆棧爲文件

jhat -J-Xmx2048m -port 5000 /tmp/m.hprof

在線查看堆文件的類,速度比較慢

jcmd PID GC.run

強制gc

如何排查?

1.開發環境和測試環境調試

使用jdk自帶的jvisualvm.exe,查看佔空間的類和實例最多的類,找到其最近的內存釋放點一般就是內存泄漏的對象。
也可以使用jmap查看jvm進程實例最多的類。

  • 本機啓動程序,postman或jmeter調用接口,可以直接用jvisualvm查看堆棧信息
  • 遠程調試,在測試環境啓用jmxremot,如下:
Dcom.sun.management.jmxremote.port=10096 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false

但是堆棧信息只能先保存在測試服務器上,下載到本地後再用jvisualvm.exe打開

2.保存生產環境的內存進行分析

先使用jmap命令將程序的內存數據保存下來,jmap -dump:live,format=b,file=m.hporf PID,其中PID是程序的進程號:

/data/server/jdk/jdk1.8.0_171/bin/jmap -dump:live,format=b,file=/tmp/m.hprof 3478

將/tmp/m.hprof堆棧文件下載到本地電腦,jvisualvm.exe打開分析
用mat分析,在空閒同網段生產服務器使用,阿里雲內網傳輸文件很快,將下載的mat直接解壓縮就可以使用了,文件如果太大需修改 MemoryAnalyzer.ini中的參數爲-Xmx4096M。

cd /data/tools/mat
./ParseHeapDump.sh 
/tmp/m.hprof 
org.eclipse.mat.api:suspects 
org.eclipse.mat.api:overview 
org.eclipse.mat.api:top_components

程序執行完,會在/tmp下生成一些文件,其中m_System_Overview.zip ,m_Top_Components.zip,m_Leak_Suspects.zip三個壓縮文件就是報告,可以看到程序的運行概況,最大的對象,和推測泄露點。
在這裏插入圖片描述
從我的內存泄露報告中可以看到Global對象groovy.lang.MetaClassImpl對象是兩個主要的內存泄露點。

如何解決?

發現問題了,該如何解決。

方法1

覆盤程序問題,將groovy腳本封裝在ThreadLocal中,在一次請求中可以被重複利用,該ThreadLocal包括了Global對象,在函數處理 **結束後釋放掉ThreadLocal**對象,主要內存泄漏點即可修復。

方法2

groovy.lang.MetaClassImpl泄露解決,先升級groovy-all的版本,發現很多實例其實已經不再引用,但是內存卻無法釋放,當系統內存不足的時候纔會被釋放掉。

最終解決

spring-boot 升級到2.1.1.RELEASE

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.1.RELEASE</version>
    <type>pom</type>
</dependency>

廢用tomcat容器,改用undertow當做容器

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
	<exclusions>
		<exclusion>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-tomcat</artifactId>
		</exclusion>
	</exclusions>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>

java啓動參數的順序調整

生產環境的spring boot工程-Xmx出現有的生效,有的無效,並且所有的jar包jvm參數全放到jar包後面。調整一下順序,如下:

java -jar -Xmx2048m -Xms1024m test.jar --spring.profiles.active=prod

注:本地電腦調整順序無效,在生產有效。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章