相信你們都有感觸,線上服務內存OOM的問題,是最難定位的問題,不過歸根結底,最多見的緣由:服務器
自己資源不夠網絡
申請的太多多線程
資源耗盡架構
58到家架構部,運維部,58速運技術部聯合進行了一次線上服務內存OOM問題排查實戰演練,將內存OOM問題定位三板斧分享出來,但願對你們也有幫助。運維
題目ssh
某服務器上部署了Java服務一枚,出現了OutOfMemoryError,請問有多是什麼緣由,問題應該如何定位?socket
不妨設服務進程PID爲10765(沒錯,就是CPU佔用高的那個倒黴的進程《線上服務CPU100%問題快速定位實戰》)。工具
解決思路線程
Java服務OOM,最多見的緣由爲:3d
有多是內存分配確實太小,而正常業務使用了大量內存
某一個對象被頻繁申請,卻沒有釋放,內存不斷泄漏,致使內存耗盡
某一個資源被頻繁申請,系統資源耗盡,例如:不斷建立線程,不斷髮起網絡鏈接
更具體的,能夠使用如下的一些工具逐一排查。
1、確認是否是內存自己就分配太小
方法:jmap -heap 10765
如上圖,能夠查看新生代,老生代堆內存的分配大小以及使用狀況,看是否自己分配太小。
2、找到最耗內存的對象
方法:jmap -histo:live 10765 | more
圖示:
如上圖,輸入命令後,會以表格的形式顯示存活對象的信息,並按照所佔內存大小排序:
實例數
所佔內存大小
類名
是否是很直觀?對於實例數較多,佔用內存大小較多的實例/類,相關的代碼就要針對性review了。
上圖中佔內存最多的對象是RingBufferLogEvent,共佔用內存18M,屬於正常使用範圍。
若是發現某類對象佔用內存很大(例如幾個G),極可能是類對象建立太多,且一直未釋放。例如:
申請完資源後,未調用close()或dispose()釋放資源
消費者消費速度慢(或中止消費了),而生產者不斷往隊列中投遞任務,致使隊列中任務累積過多
3、確認是不是資源耗盡
工具:
pstree
netstat
查看進程建立的線程數,以及網絡鏈接數,若是資源耗盡,也可能出現OOM。
這裏介紹另外一種方法,經過
/proc/${PID}/fd
/proc/${PID}/task
能夠分別查看句柄詳情和線程數。
例如,某一臺線上服務器的sshd進程PID是9339,查看
ll /proc/9339/fd
ll /proc/9339/task
如上圖,sshd共佔用了四個句柄
0 -> 標準輸入
1 -> 標準輸出
2 -> 標準錯誤輸出
3 -> socket(容易想到是監聽端口)
sshd只有一個主線程PID爲9339,並無多線程。
因此,只要
ll /proc/${PID}/fd | wc -l
ll /proc/${PID}/task | wc -l (效果等同pstree -p | wc -l)
就能知道進程打開的句柄數和線程數