服務器報警:內存超95%
服務器報警:內存超95%
背景:
收到阿里云監控報警:服務器內存占用太高
,
和運維同事溝通了解后 這臺機器上運行著另外一家公司的java項目, 這個項目啟動后,內存會逐漸升高,直到95%就不變了,一直居高不下,這個問題已經很長時間了,由于涉及另外一家公司,而且似乎項目運行功能也沒問題,只是多占些服務器資源,就一直沒排查。
本著好奇的態度,我決定查查怎么回事
排查步驟:
- top發現java進場內存使用率比較高,首先想到的是看日志,但是并沒有OOM的記錄
- 按照一般的想法,還是要導出dump文件,看看內存里都是什么對象, 之前比較熟練是 用arthas導出
https://arthas.aliyun.com/doc/
有些命令記不清,每次用arthas都是到這個網頁去找。
遇到一個問題:
[arthas@58205]$ heapdump arthas-output/dump.hprof
Dumping heap to arthas-output/dump.hprof ...
Heap dump file created
執行后找不到文件去哪兒了,查了半天發現 arthas-output 是 自動在tomcat的bin目錄下
dump.hprof文件比較大 4G, 壓縮tar -vczf 后下載下來
3.用MAT打開dump.hprof文件,打開dominator_tree

發現最大是 java.lang.ref.Finalizer ,再點開 發現它好像是個鏈表結構,一直next

既然是鏈表結構,它節點本身是什么呢,看到referent 是 java.util.zip.ZipFile
查看ZipFile的outgoing

發現是arthas的jar,肯定是找錯了。 又查了幾個next 還是 arthas的jar, 肯定不是arthas引起的,那么到底是什么引起的呢 。 這個Finalizer 這么大,有沒有辦法統計出每個next里分別是什么對象呢, 去網上查資料,終于找到一個類似的帖子:
https://blog.csdn.net/shy_1023/article/details/135238034
帖子里提到可以用 OQL 查詢
SELECT z.clazzName AS clazzName, z.maps AS Maps, z.maps.@length AS Count
FROM OBJECTS ( eval((SELECT s.sz AS clazzName, (SELECT OBJECTS m FROM java.lang.ref.Finalizer m WHERE (toString(m.referent.@clazz.@name) = s.sz)) AS maps FROM OBJECTS ( SELECT DISTINCT toString(h.referent.@clazz.@name) AS sz FROM java.lang.ref.Finalizer h ) s )) ) z
按F5執行發現 最多的是SocksSocketImpl

通過SocksSocketImpl incoming outgoing 一頓找 (incoming 是看哪些對象包含當前對象, outgoing是看 當前對象包含什么),終于找到了認識的 jdbc

再往下找就找不到了。
4.然后就繼續在網上找資料,終于找到了一個帖子:
https://blog.csdn.net/MakeContral/article/details/76615377
https://blog.csdn.net/u014365523/article/details/127513012
同時反編譯了下 對方的代碼,發現數據庫連接沒有使用線程池,里面有定時任務,1分鐘執行一次, 一次里面有多個數據庫查詢操作, 每個查詢總是新建數據庫連接 關閉連接
大概理解的意思是: jdbc 連接 有重寫 finalize() 方法,這導致資源釋放不及時,好多對象被 java.lang.ref.Finalizer 引用, jvm不會立馬殺掉它。
中間還嘗試了 jcmd命令, dashborard命令
5.另外發現似乎內存升高和 超大文件的IO有關系,沿著這個方向找也沒查到特別有價值的資料。
解決方式:
跟蹤了兩天還是沒有完全搞清楚原因,先嘗試修改JVM參數,發現之前用的CMS收集器, 改為G1 收集器 -XX:+UseG1GC,據說G1 回收效率比較高,另外加了-XX:MaxDirectMemorySize=200m 防止使用Direct 內存太多。后續有時間再跟蹤。
總結:
雖然沒有徹底解決問題,但是通過這次跟蹤 還是學到了一些知識:
- OQL的作用,之前只是知道并沒有真正用過
- Finalizer 的原理, 鏈式結構,GC慢
- 理解了 數據庫連接池化的好處
- JVM的一些參數

浙公網安備 33010602011771號