JVM從入門到入土之實戰G1垃圾回收器(二)

前言

文本已收錄至個人GitHub倉庫,歡迎Star:github.com/bin39232820…
種一棵樹最好的時間是十年前,其次是如今
我知道不少人不玩qq了,可是懷舊一下,歡迎加入六脈神劍Java菜鳥學習羣,羣聊號碼:549684836 鼓勵你們在技術的路上寫博客git

絮叨

前面的章節github

回顧

上面一篇文章你們其實能夠搞懂G1的動態內存管理策略,它會根據狀況動態的把Regiuon分配給 新生代,Eden,Survivor,老年代和大對象,可是新生代和老年代有一個各自最大的佔比,而後在新生代Eden滿的時候,觸發新生代垃圾回收。算法

新生代的垃圾回收仍是採用了複製算法,只不過會考慮預設的GC停頓時間,保證垃圾回收的停頓時間不難超過設置的時間,所以會挑選一些Region來進行垃圾回收。併發

而後跟以前說的同樣,若是一些對象在新生代熬過拉框必定次數的GC,或者觸發了動態年齡斷定規則,則會進入老年代工具

而大對象則是進入單獨的Regin,再也不進入老年代佈局

因此實際上在G1中,仍是會存在新生代的對象會由於各類狀況進入老年代post

何時G1觸發新生代+老年代混合垃圾回收?

G1 有個參數 是-XX:InitiatingHeapOccupancyPercent 它的默認值是45%性能

意思是說 若是老年代佔了 堆內存的45%的Region的時候,此時就會觸發混合回收階段 以下圖學習

G1垃圾回收的過程

首先會觸發一個 初始標記的操做,這個過程須要 Stop the world 的,可是這個過程很快測試

以下圖,先中止系統程序的運行,而後對各個線程棧內存中的局部變量表明GC Roots,以及方法區表明靜態變量的Roots,進行掃描,標記出他們直接引用對象。

接下來就會進入到 併發標記的階段,這個階段會容許系統程序繼續運行,同時進行GC Root追蹤,以下圖所示

這個併發標記階段仍是很耗時的,由於要追蹤所有的存活對象

可是這個階段是能夠跟系統程序併發進行的,因此對系統程序的影響不太大

並且JVM會對併發標記階段對象作出一些記錄,好比哪一個對象新建了,哪一個對象失去引用了,等等

接着下一個階段就是 最終標記階段,這個階段也會進入Stop the world ,系統程序是禁止運行的,可是會根據併發標記記錄那些 對象修改,最終標記哪些對象存活,以下圖所示

最後一個階段 是混合回收階段,這個階段會計算老年代每一個Region中的存活對象數量,存活對象佔比,還有執行垃圾回收的預期性能和效率。

接着會中止系統程序,而後盡心盡力儘快進行回收,此時會選擇部分Region進行回收,由於必須讓垃圾回收的停頓時間控制在咱們指定的範圍內。

好比說 老年代此時有1000Region都滿了,可是由於設置的時間,只能停頓200ms,不那麼我只能回收800個,那麼就會只回收800個Region,把GC的時間控制在咱們指定的範圍以內,以下圖

案例背景引入

這是一個百萬級註冊用戶的在線教育平臺,主要目標用戶羣體是幾歲到十幾歲的孩子,註冊用戶大概是幾百萬的規模,日活躍規模大概在幾十萬。

系統的業務流程其實也不復雜,並且咱們能夠排除掉一些選課,排課,瀏覽課程詳情這些低頻行爲。

爲啥呢?由於它不是一個電商平臺,不是說每一個人進去都會去瀏覽課程詳情, 因此 通常的業務流程就是,有人進來瀏覽一下,考慮一段時間,而後買拉課程,因此它的高頻行爲是什麼呢?我想了一下,應該是上課

也就是說,孩子們白天要在學校上課,通常也是晚上 8 9點的樣子,是這個平臺最活躍的時候,還有就是週末也是最活躍的時候,

因此晚上二三個小時的時間段,將會是平臺的高峯期,並且白天幾乎沒有什麼流量,可能90%的流量讀在晚上,以下圖所示

系統核心業務流程

接着咱們來明確一下,這樣的一個系統,孩子們在上課的時候主要高頻的使用哪些功能呢

其實很是的簡單,如今若是你們家裏有孩子,平時對一些在線教育App有必定的瞭解的話,應該知道如今在線App都會主打互動環節

給你們舉個例子,好比說給五六歲的孩子上的幼兒園英語課,你們以爲還會像之前同樣嗎,機械的跟讀嘛

那確定不是了,如今尤其強調的是在歡快的愉快的遊戲中進行教學,讓孩子們快樂的學習英語,數學之類學科的知識

因此說 在那幾十萬用戶 晚上最高峯的時間使用系統上課的時候,尤其核心的業務流程就是大量的遊戲互動環節

也就是說,這個遊戲互動功能,必定會承擔用戶高頻點擊,大量的互動點擊

好比在完成什麼任務的時候必須點擊不少的按鈕,頻繁的進行互動,而後系統後臺須要大量的接收大量的互動請求,並記錄用戶互動的結果,

系統得記錄下來用戶完成了多少個任務,做對了幾個,作錯了幾個。

系統的運行壓力

如今咱們開始來分析一下這個系統運行時候對內存使用的一個壓力

其實核心點就是搞明白晚上二三個小時高峯期內,每秒鐘會有多少請求,每一個請求會連帶產生多少對象,佔用多少內存,每一個請求處理多長時間。

首先咱們來分析一下晚上高峯期內幾十萬用戶同時在線使用平臺,每秒鐘會產生多少請求?

咱們能夠大體來估算一下,好比說晚上3小時高峯期內總共60萬活躍用戶,平均每一個用戶大概會使用1小時左右來上課,一個小時內會進行60次互動操做

那麼20W活躍用戶由於須要大量的互動操做,因此大體能夠認爲是每分鐘進行1次互動操做,一小時內會進行60次互動操做

那麼20萬用戶在1小時內會進行1200萬次互動操做,平均每秒大概是3000次左右的互動操做,這個是一個很合理的數字

那麼每秒要承載3000併發請求,根據經驗來看 通常核心系統須要部署5臺 4核8G的機器來抗住是差很少的,每臺機器能抗住600請求,這個壓力能夠接受,通常不會致使宕機問題。

那麼每一個請求會產生多少個對象呢?

一次互動請求不會有太複雜的對象,他主要是記錄一些用戶互動過程的,可能會跟一些積分類的東西有關聯

因此大體估算一下,一次互動請求大體會連帶建立幾個對象,佔多大的內存,好比咱們就認爲是5kb吧那麼一秒600請求會佔用3MB左右的內存

G1垃圾回收的默認內存佈局

接着咱們來看看G1垃圾回收器的默認內存佈局,咱們採用4核8G的機器來部署系統,而後每臺機器每秒會有600個請求會佔用3Mb左右的內存空間。

那麼假設咱們對機器上的JVM,分配4G給堆內存,其中新生代默認初始佔比5%,最大佔比60%,每一個Java線程的棧內存爲1MB,元數據區域的內存爲256M,此時的JVM參數以下

-XX:G1NewSizePercent 參數是用來設置新生代初始佔比的,不用設置,維持默認值5%就能夠了

-XX:G1MaxNewSizePercent 參數是用來設置新生代最大佔比的,也不用設置 維持默認的60%就能夠了

此時堆內存共4G,那麼此時會除以2048,計算每一個Region的大小,此時每一個Region的大小就是2MB,剛開始新生代就佔5%的Region,能夠認爲新生代就只有100個Region,有200MB的內存空間,以下圖所示。

設置GC停頓時間

在G1垃圾回收器中有一個相當重要的參數會影響到GC的表現,就是 -XX:MaxGCPauseMills,它的默認值是200毫秒

也就是咱們每次觸發GC的時候致使的系統停頓時間 Stop the world 不要超過200ms,避免系統由於GC長時間卡死。

這個參數咱們能夠先保持一個默認值,繼續往下分析看看,不着急忙下結論

到底多長時間會觸發新生代GC?

有一個問題,就是系統運行起來以後,會不停的在新生代的Eden區域分配對象,按照以前的推算是每秒分配3MB的對象,以下圖

那何時Eden的區域會不夠呢?

前面咱們說過 -XX:G1MAXNEWSIZE參數規定了新生代最大的堆內存空間

那麼難道必須得隨着系統運行一直給新生代分配更多得Region,直到新生代佔據了60%以後,再進行GC?

G1確定不是這樣玩的

咱們假設G1回收300Region須要 200ms

那麼頗有可能系統運行時,G1呈現出現以下的運行效果

首先,隨着系統運行,每秒建立3MB的對象,大概1分鐘左右就會塞滿100個Region,以下圖所示

此時極可能G1會以爲 ,要是我如今就觸發GC,那麼回收區區200MB 只須要大概幾十ms,最多就讓系統中止幾十ms而已,跟個人主人設定的參數200Ms還相差很遠。

若是如今gc, 那麼每分鐘都要GC會不會太頻繁了,好像沒有這個必要

因此還不如給新生代先增長一些Region,而後讓系統繼續運行再新生代Region中分配對象好了,這樣就不用過於頻繁觸發新生代gc了,此時如圖所示

而後系統繼續進行,一直到可能300個Region都佔滿了,此時經過計算髮現回收300個Region大概須要200ms,那麼可能這個時候就會觸發一次新生代gc了

G1是很是靈活的,它會根據你設置的時間 給新生代不停的分配更多Region

而後到必定程度,感受差很少了,就會觸發新生代gc,保證新生代Gc的時候致使的系統停頓時間再你預設的範圍內

新生代如何優化

其實就是優化-XX:MaxGCPauseMills參數

若是這個參數設置小了 ,那麼說明每次gc的停頓時間很短,可是很頻繁

若是這個參數設置大了 停頓的時間就會很是長,

因此這個參數到底如何設置,須要結合工具來測試,來達到一個合理的值

老年代如何優化

其實也是核ParNew +CMS 控制沒必要要的對象進入老年代就行了,也是-XX:MaxGCPauseMills這個參數,

你們能夠想象一下 若是這個參數很大,那麼通過新生代的gc後,就會致使Survivor區域放不下那麼多的對象,那麼這些對象就會進入老年代了

或者是由於動態年齡判斷進入老年代了,因此說仍是設置這個參數

結尾

其實也就是把G1簡單的說了一下,後面還有具體的乾貨

由於博主也是一個開發萌新 我也是一邊學一邊寫 我有個目標就是一週 二到三篇 但願能堅持個一年吧 但願各位大佬多提意見,讓我多學習,一塊兒進步。

平常求贊

好了各位,以上就是這篇文章的所有內容了,能看到這裏的人呀,都是真粉

創做不易,各位的支持和承認,就是我創做的最大動力,咱們下篇文章見

六脈神劍 | 文 【原創】若是本篇博客有任何錯誤,請批評指教,不勝感激 !

相關文章
相關標籤/搜索