JAVA應用內(nèi)存泄漏排查記錄

最近公司的一臺服務器頻繁報警,老大讓我研究下代碼出了什么問題,咋一看才知道代碼是用大名鼎鼎的異步框架Vert.x寫的,本文記錄本菜鳥排查問題的辛酸過程,僅作為以后的一點經(jīng)驗參考。本服務器阿里云雙核ECS實例,2G內(nèi)存,CentOS7系統(tǒng)。

1.查看服務器硬盤內(nèi)存狀況

top #查看服務器內(nèi)存和硬盤容量

top

看了下參數(shù),以為這些挺重要的,其實發(fā)現(xiàn)CPU和Mem都很正常,內(nèi)存看似要用完了,其實free+buffers+cached大概容量也有900M,完全夠用。

2.查看服務器進程的堆棧

jcmd #查看進程,發(fā)現(xiàn)有兩個java項目,一個是公司的web項目,另一個是報警的Vertx項目
jinfo [pid] 查看堆內(nèi)存,發(fā)現(xiàn)一個項目的內(nèi)存參數(shù)-Xms1450M,本項目采用的默認配置,暫時看不出分配多少內(nèi)存
or ps aux | grep tomcat | grep -v grep  查看初始內(nèi)存使用
jstack [pid] 看棧信息,發(fā)現(xiàn)很多歌vert.thread在等待,因為服務器相應緩慢,看了下Log,看到了NPE

初步分析,NullPointerException導致了服務器相應緩慢。
首先調(diào)查,為什么會NullPointerException,根據(jù)Log很容易找到原因,最后配合前端同事知道新版本的前端請求格式不對造成報錯。
那么問題來了,報錯為什么會導致應用相應緩慢。可能是連接沒有釋放,或者是持久層插入錯誤數(shù)據(jù)報錯沒有釋放連接。

3 查看進程具體內(nèi)存

jinfo [pid] 查看到初始化的配置 

看到Vertx最大堆內(nèi)存300M,old區(qū)只有50M,這個我很納悶,照理說默認配置新生區(qū)和old區(qū)比例是1:2起碼也有200M,這樣不會oom嗎。

jmap -heap [pid] 查看堆內(nèi)存各個分區(qū)大小,old區(qū)使用率90%以上,如果加大Old,如果還不行,肯定是內(nèi)存泄漏了,就是對象沒有釋放。
jstat -gcutil [pid] 1s 發(fā)現(xiàn)最近發(fā)生了6次FGC old區(qū)依然降不下去

果然過了一天,log就出現(xiàn)了heap Out Of Memory.

4 嘗試增加虛擬機內(nèi)存分配

javaweb項目部署在tomcat下,系統(tǒng)為它分配了1450M的內(nèi)存,打開tomcat/bin/catalina.sh,修改

JAVA_OPTS= -Xms1000M -Xmx1000M,這里保證初始分配內(nèi)存和最大堆內(nèi)存相同,放置系統(tǒng)調(diào)整內(nèi)存空間產(chǎn)生的消耗。

同時給報警的Vertx項目增加內(nèi)存,

java -Xms700M -Xmx700M -jar >>t.log 2>&1 & 將標準輸出重定向
參數(shù)說明如下
-Xms 初始化對內(nèi)存
-Xmx 最大堆內(nèi)存
-Xss每個線程內(nèi)存
-XX:PermSize設置非堆內(nèi)存初始值,默認是物理內(nèi)存的1/64
-XX:MaxPermSize設置最大非堆內(nèi)存的大小,默認是物理內(nèi)存的1/4

重啟項目后,過一段時間繼續(xù)查看

jmap -heap [pid] 發(fā)現(xiàn)堆內(nèi)存Old區(qū)飆升,還是達到了90%

5 查看代碼,檢查內(nèi)存泄漏位置

jstat -gcutil [pid] 60000  查看從程序啟動到現(xiàn)在進行了多少FGC,查看下old區(qū)百分比
jmap -histo:live [pid] >f 打印堆內(nèi)存存活對象信息
vi f

通過查看對象信息,從上往下發(fā)現(xiàn)有個對象EventItem被實例化了10w+次,這個類里面包含的數(shù)組,對象數(shù)組響應實例化次數(shù)也和其他不在同一數(shù)量級。確定是這個問題,回到代碼中,我找到了初始化該對象的位置,應該是報錯之后,request沒有釋放,request里面的private對象UploadRequest沒有釋放,導致錯誤的EventItem也無法釋放。
于是我在出錯的try.catch語句中直接將整個請求return,因為這些數(shù)據(jù)其實都是些無效的數(shù)據(jù),直接return也可以節(jié)約不少開銷。

后續(xù)觀察

修改代碼后,重新發(fā)布,已近觀察3天,出錯項目的heap的old區(qū)使用率終于降下來了,dump了對象信息也沒有大量的EventItem,服務器運行終于正常,說明問題解決了。這個過程中經(jīng)歷了一些坑,比如錯誤的以為是另外一個項目影響造成,浪費了不少時間排查,不過學到不少東西。
jinfo/jmap/jstat這些命令是調(diào)優(yōu)時候常用的,dump出文件查看對象信息,jconsole監(jiān)控本地jvm運行狀況,通過修改jvm參數(shù)調(diào)整服務響應時間等等。
代碼沒有貼出來,具體信息也沒細說,因為涉及公司項目還是保密為好,文章就留著以后回顧下吧。
個人博客 歡迎訪問~

祝大家編碼愉快,工作愉快,歡迎關(guān)注我的公眾號,一起分享交流


Java技術(shù)小棧
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,688評論 18 399
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,030評論 25 709
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,554評論 19 139
  • 其實大學之前一直是個瘦子,我個子小,一直都是八十多斤。后來大學畢業(yè)時因為月經(jīng)不調(diào)去看醫(yī)生,當時醫(yī)生給我打了一周的黃...
    niki100200閱讀 237評論 0 1
  • 意見收集 了解團隊的工作重點,以及大家對用戶體驗的重視程度和支持程度。 方法概述 只有了解同事(尤其是項目關(guān)鍵人物...
    z嘉嘉嘉閱讀 639評論 0 0

友情鏈接更多精彩內(nèi)容