jvm內存過高及那些對象導致內存過高,那些對象不會被gc回收


JVM調試和優化(一)

概述

事情發生的過程是這樣的

有一天突然收到亞馬遜amazon的郵件說我的web服務cpu over max , memory 也over max 了 ,這一刻,我的內心是崩潰的 , 心里設想了一萬種意外和不可能是程序問題的理由 . 事實是太天真了,不是程序問題才怪 . 臨時處理方式是重啟服務 ,畢竟內存和cpu使用率爆棚還是需要很長時間的 , 這段時間可以排查到底是因為什么 .

一些可能導致OOM即內存溢出的原因

  1. 堆內存設置太小
  2. 永久代設置太小(java8已不存在這個問題,因為metaspace已經替代了perm)
  3. 代碼中創建了很多大對象 , 且一直因為被引用不能被回收
  4. 長生命周期對象持有短生命周期對象的引用
  5. 靜態集合類引起的內存泄漏 , 例如HashMap和Vector等
    因為他們是靜態的, 他們的生命周期與應用一致 , 所以他們引用的對象不會被釋放 , 所以需要特別注意自己是否有靜態集合存了許多對象的情況
  6. 單例模式
    單例對象初始化后再JVM整個生命周期中存在 , 如果單例對象持有對外部對象的引用那么整個對象不會被JVM回收
  7. 全局集合
  8. 類加載器

逐個分析和排除

1和2設置過小的問題

逐個比較好解決 , 合理增大設置或增大硬件物理內存即可 ,這里可能要說的是metaspace如果不設置會有一個默認值 , 會很小 , 但是它會在不夠用的時候自動增大 ,直逼最大物理內存 .(此變更可以某種程度是可以避免OOM)具體請百度或Google本人不再贅述 .

3 代碼中創建了很多大對象 , 且一直因為被引用不能被回收

第一步,使用jmap -heap pid查看堆使用情況

查看堆使用情況

第二步, 使用jmap -histo:live pid 查看實例數和實例所占內存大小

查看實例情況

第三步, 統計所有實例所占內存大小

jmap -histo:live 17863|awk ‘{if(NR>3)a+=$3}END{print a}’
233455600
這個單位是byte , 換算后222.64061MB

大對象倒是沒有 , 但是[C代表字符的數組占用了大多數的內存空間 , 雖然現在講示例時它占得少 ,實際當內存接近90%時 ,字符數組還是在第一位 .([B表示布爾數組]) , 結論是不存在特別多的大對象占用了內存空間 , 字符數組雖然也占了很多內存但不是導致內存溢出的主要原因.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM