現象: 某個服務上線後,發現運行幾天時間後,就沒有響應了,也沒有日誌輸出。以前的日誌裏面也沒有任何異常。
猜想 : 進程也在,nginx等日誌都正常,數據庫也正常,懷疑就是服務有內存泄露。
排查思路
1. 生產環境不能影響正常服務,出現問題後,運維第一時間作了重啓,現場就沒了。而後用寫了shell先定時重啓(多臺暫不間斷提供服務)。
2. 接下來,就使用jmap看內存的對象數量了,整體來時只增不減的就是有問題的。同時,也作了個單獨的測試環境,運行起來服務,準備重現問題。
3. 如下以重現的測試環境爲例,首先找到進程號(假設是1302)java
(1) 使用 jmap -heap 1302 先看一下堆的狀況
Attaching to process ID 1302, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.131-b11nginx
using thread-local object allocation.
Parallel GC with 8 thread(s)git
Heap Configuration:
MinHeapFreeRatio = 0
MaxHeapFreeRatio = 100
MaxHeapSize = 4164943872 (3972.0MB)
NewSize = 87031808 (83.0MB)
MaxNewSize = 1388314624 (1324.0MB)
OldSize = 175112192 (167.0MB)
NewRatio = 2
SurvivorRatio = 8
MetaspaceSize = 21807104 (20.796875MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 17592186044415 MB
G1HeapRegionSize = 0 (0.0MB)github
Heap Usage:
PS Young Generation
Eden Space:
capacity = 9437184 (9.0MB)
used = 9100328 (8.678749084472656MB)
free = 336856 (0.32125091552734375MB)
96.43054538302951% used
From Space:
capacity = 2621440 (2.5MB)
used = 0 (0.0MB)
free = 2621440 (2.5MB)
0.0% used
To Space:
capacity = 3145728 (3.0MB)
used = 0 (0.0MB)
free = 3145728 (3.0MB)
0.0% used
PS Old Generation
capacity = 2776629248 (2648.0MB)
used = 2776562952 (2647.9367752075195MB)
free = 66296 (0.06322479248046875MB)
99.99761235677944% usedspring
26258 interned Strings occupying 3126264 bytes.shell
能夠看到, PS Old Generation的空間已經佔盡了,程序無響應就是這個狀況的直接後果。數據庫
(2) 那就打印一下內存的對象佔用狀況,內容較多,就把內容輸出到一個文本。
jmap -histo -F ${pid} > /xxx/logs/jmap.log apache
內容以下:運維
Attaching to process ID 1302, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.131-b11
Object Histogram:jvm
num #instances #bytes Class description
--------------------------------------------------------------------------
1: 7393486 177443664 java.lang.String
2: 3653036 146121440 org.apache.kafka.clients.consumer.ConsumerRecord
3: 3653040 87672960 java.util.concurrent.LinkedBlockingQueue$Node
看了一下,ConsumerRecord 數量不少,和業務邏輯不符合(備註:線上環境能夠持續關注這個對象的數量,若是持續的只增長不回收,就要注意了),且不被回收減小。
(3) 去項目程序看,使用這個對象的地方,通過排查,項目程序並沒有引用問題。使用這個對象的地方是,kafka的消費者Listener,對象由spring-kafka提供。因而懷疑是第三方spring kafka的bug。
(4) 經查, 我找到了這個兩個issue。
https://github.com/spring-projects/spring-kafka/pull/162
https://github.com/spring-projects/spring-kafka/issues/161
查看issue的內容, 確認了一下版本號,咱們用的依賴jar, 是在這個issue解決以前的。那這個對咱們有影響,符合邏輯推演。由於咱們的隊列量不大不小,一直不回收,就會有這個問題。
(5) 更新版本,從新上線或測試環境, 觀察heap使用狀況。
參考:
JDK內置工具使用: http://blog.csdn.net/fenglibing/article/details/6411924
jvm查內存泄漏利器 - jmap: http://www.wujianjun.org/2016/09/21/jvm-tools-jmap/
FIXING SUN.JVM.HOTSPOT.DEBUGGER.DEBUGGEREXCEPTION: CAN’T ATTACH TO THE PROCESS: https://zenidas.wordpress.com/recipes/fixing-sun-jvm-hotspot-debugger-debuggerexception-cant-attach-to-the-process/
使用堆外內存: http://www.raychase.net/1526