【性能調優】JNI內存溢出案例(String對象溢出)

前言

場景: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-*),這樣會減少問題定位的難度

 

 

 


愛家人,愛生活,愛設計,愛編程,擁抱精彩人生!

發佈了94 篇原創文章 · 獲贊 232 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章