前言
場景:C++通過JNI將數據傳輸給Java程序
問題:運行一段時間String對象和Char字符不停變大,直到內存溢出(JVM-OOM)
1 過程
- Jmap初步分析頭部對象內存佔用
PS:jmap -histo:live <pid>,執行該方法會同步執行一次GC,所以,展示的都是無法GC的對象。
發現:String對象有28萬個,可能存在String對象被長期持有的現象,初步懷疑是HashMap等緩存持有
- Jmap導出堆棧分析:導出堆棧時String對象是21萬個
jmap -dump:live,format=b,file=/root/edr.bin 17994
- 用eclipse-mat打開堆棧文件:通過Histogram看看對象實例數
發現:String對象確實是21萬個
- 看看String對象來自於哪裏,並將String列表按RetainedHeap倒敘排列
發現:String對象是來自於本地JNI線程,且這個JNI線程還持有大量的內存
- 查看程序線程內存佔用情況
發現:存在10個相似的線程,都佔用了很多內存,且線程類型還是守護類型,但是無法通過線程名判斷是什麼線程對象
- 查看線程持有哪些對象
發現:線程持有14759個String對象,基本可以判斷是該類(10個)線程沒有將JNI-String內存釋放
- 最終確認確實是C++JNI相關代碼沒有釋放內存
2 總結
- 靈活應用對象持有和對象被引用關係,來分析內存
- 線程名儘量按模塊命名,不要使用默認命名(Thread-*),這樣會減少問題定位的難度
愛家人,愛生活,愛設計,愛編程,擁抱精彩人生!