內存問題-JVM調優思路

一般,內存的問題就是 GC 的問題,由於 Java 的內存由 GC 管理。有2種狀況,一種是內存溢出了,一種是內存沒有溢出,但 GC 不健康。java

內存溢出的狀況能夠經過加上數據結構

-XX:+HeapDumpOnOutOfMemoryError,該參數做用是:在程序內存溢出時輸出 dump 文件。oracle

-XX:HeapDumpPath=/export/Logs/heap_dump_oom.hprof,jvm

有了 dump 文件,就能夠經過 dump 分析工具進行分析了,好比經常使用的MAT,Jprofile,jvisualvm 等工具均可以分析,這些工具都可以看出究竟是哪裏溢出,哪裏建立了大量的對象等等信息。工具

第二種狀況就比較複雜了。GC 的健康問題。優化

一般一個健康的 GC 是什麼狀態呢?根據樓主的經驗,YGC 5秒一次左右,每次不超過50毫秒,FGC 最好沒有,CMS GC 一天一次左右。spa

而 GC 的優化有2個維度,一是頻率,二是時長操作系統

咱們看YGC,首先看頻率,若是 YGC 超過5秒一次,甚至更長,說明系統內存過大,應該縮小容量,若是頻率很高,說明 Eden 區太小,能夠將 Eden 區增大,但整個新生代的容量應該在堆的 30% - 40%之間,eden,from 和 to 的比例應該在 8:1:1左右,這個比例可根據對象晉升的大小進行調整。日誌

若是 YGC 時間過長呢?YGC 有2個過程,一個是掃描,一個是複製,一般掃描速度很快,複製速度相比而言要慢一些,若是每次都有大量對象要複製,就會將 STW 時間延長,還有一個狀況就是 StringTable ,這個數據結構中存儲着 String.intern 方法返回的常連池的引用,YGC 每次都會掃描這個數據結構(HashTable),若是這個數據結構很大,且沒有通過 FGC,那麼也會拉長 STW 時長,還有一種狀況就是操做系統的虛擬內存,當 GC 時正巧操做系統正在交換內存,也會拉長 STW 時長。對象

再來看看FGC,實際上,FGC 咱們只能優化頻率,沒法優化時長,由於這個時長沒法控制。如何優化頻率呢?

首先,FGC 的緣由有幾個,

1 是 Old 區內存不夠,

2 是元數據區內存不夠,

3 是 System.gc(),

4 是 jmap 或者 jcmd,

5 是CMS Promotion failed 或者 concurrent mode failure,

6 JVM 基於悲觀策略認爲此次 YGC 後 Old 區沒法容納晉升的對象,所以取消 YGC,提早 FGC。

一般優化的點是 Old 區內存不夠致使 FGC。若是 FGC 後還有大量對象,說明 Old 區太小,應該擴大 Old 區,若是 FGC 後效果很好,說明 Old 區存在了大量短命的對象,優化的點應該是讓這些對象在新生代就被 YGC 掉,一般的作法是增大新生代,若是有大而短命的對象,經過參數設置對象的大小,不要讓這些對象進入 Old 區,還須要檢查晉升年齡是否太小。若是 YGC 後,有大量對象由於沒法進入 Survivor 區從而提早晉升,這時應該增大 Survivor 區,但不宜太大。

上面說的都是優化的思路,咱們也須要一些工具知道 GC 的情況。

JDK 提供了不少的工具,好比 jmap ,jcmd 等,oracle 官方推薦使用 jcmd 代替 jmap,由於 jcmd 確實能代替 jmap 不少功能。jmap 能夠打印對象的分佈信息,能夠 dump 文件,注意,jmap 和 jcmd dump 文件的時候會觸發 FGC ,使用的時候注意場景。

還有一個比較經常使用的工具是 jstat,該工具能夠查看GC 的詳細信息,好比eden ,from,to,old 等區域的內存使用狀況。

還有一個工具是 jinfo,該工具能夠查看當前 jvm 使用了哪些參數,而且也能夠在不停機的狀況下修改參數。

包括咱們上面說的一些分析 dump 文件的可視化工具,MAT,Jprofile,jvisualvm 等,這些工具能夠分析 jmap dump 下來的文件,看看哪一個對象使用的內存較多,一般是可以查出問題的。

還有很重要的一點就是,線上環境必定要帶上 GC 日誌!!!

 

參考出處: 博客園: http://www.cnblogs.com/stateis0/ 
            我的博客:  thinkinjava.cn
相關文章
相關標籤/搜索