今早收到一條短信,具體報警信息以下:算法
【UMP JVM監控內存報警】應用名:發券worker(jdos_couponwkr);KEY【coupon.send.worker.jvm】,主機名:【host-10-183-72-114】,實例【11909223645】的堆內存使用率連續3次超過設定閥值【90.0%】。報警級別:【Warning】,報警時間:【2019-07-17 07:36:12】。docker
說是有一臺機器的堆內存使用超過閾值90%。這條短信雖然言簡意賅,可是背後隱藏的技術細節,我這裏來陳述一下,謬誤之處,還請指教。jvm
初看此報警,則知道堆內存使用超過閾值了。第一反應通常都是把堆內內存調大,就好了。可是事實真的如此嗎?不妨來一塊兒看看。blog
假設咱們如今堆內內存爲1G,則堆內存使用曲線以下:內存
能夠看到總體使用正常,回收正常,很是平穩。資源
如今,咱們把堆內內存調整爲2G,則堆內內存使用曲線以下:get
能夠看到,堆內內存使用率依然超過90%,說明單純的調節堆內內存的大小,是沒法解決此問題的。it
爲何呢? 因爲jvm工做的時候,對堆內內存的使用是自適應的,你給的多,它用的多,你給的少,它用的少。因此這也是爲啥你給它1G大小,它能將堆內存用的超過90%,你給他2G大小,他也能將堆內存用的超過90%。固然,前提是應用的內存使用量大於2G才行。不然分配給2G的堆內存,則不會使用這麼高。可能用到1.5G左右就釋放了。效率
再來講說垃圾回收機制。這裏我將G1算法以外的統稱爲老算法。我們來比較一下:監控
在8G堆內存的docker上,同一個應用,同一業務,壓測結果以下:
1. young gc次數,老算法20次,G1算法8次。
2. 堆內存使用最大值,老算法使用最大6.3G,G1算法使用最大7.6G。
能夠看出,在8G堆內存的場景下,G1算法總體表現優異,更少的gc次數,更高效率的堆內存使用率。
可是在8G如下堆內存使用的場景中,G1算法則優點並不明顯。因此強烈建議堆內存比較大的應用開啓G1算法。
最後說下,遇到此短信提示須要檢查的內容。
1. 檢查yong gc耗時,平均耗時40ms之內正常,超過1s則須要排查問題。
2. 檢查full gc次數,一分鐘內數次或者數十次則顯得頻繁,須要排查。
3. 檢查堆內存回收圖形,若是內存使用率上去了,可是遲遲下不來,則意味着老年代沒法回收,檢查代碼查明緣由,相似圖形以下:
能夠看到此圖中,曲線上去後下不來,緣由是應用內部有個本地cache一直在運行且無過時機制致使,後來關閉掉此本地cache則回收正常。
4. 根據jvm使用率曲線的最高點來看當前堆內存大小是否符合設置,若是當前堆內存使用率頂點一直較高,則應用須要的內存比分配的堆內存要大一些,能夠在內存資源足夠的狀況下嘗試多分配一些堆內存。