JVM垃圾收集策略(包含G1垃圾回收器和傳統GC)

JVM垃圾回收

- jvm垃圾回收策略概述

JVM會自己選擇合適的垃圾收集策略,而用戶也可以自己來設置所需要的垃圾收集策略,但是就個人而言,強烈建議採用默認的垃圾收集處理機制。

垃圾的收集一定要分兩個空間考慮:年輕代、老年代。老年代的內存空間要大於年輕代的內存空間,所以老年代的對象每一次執行GC都會消耗更多的時間。

這裏寫圖片描述

同一種垃圾收集的策略,有可能會根據觸發內存代的不同有不同的效果,所以先來看各個內存策略的操作特點。
新生代–串行GC,一般適用單CPU
這裏寫圖片描述

年輕代 –並行回收GC–多CPU
這裏寫圖片描述

也就是說,同一個GC的處理操作需要有多個線程共同完成,一個線程負責內存的掃描(掃描出所有的不用的內存對象),而另外一個線程負責對象的複製操作。
串行回收要在其間做一個短暫的暫停(線程掛起),而並行的gc回收這個暫停時間比較短,適合多CPU。但必須有暫停。

年輕代:並行GC
這裏寫圖片描述
必須結合老年代CMS GC一起使用,並行回收GC不會這麼做。

並行回收GC只是處理年輕代的,而並行GC需要與老年代GC結合。
CMS:是以犧牲吞吐量爲代價來獲得最短回收停頓時間的垃圾回收器。對於要求服務器響應速度的應用上,這種GC非常合適。

老年代GC處理:

老年代串行GC:
這裏寫圖片描述
注意:將所有存活對象集中在一端,而後將所有回收對象的內存空間整理成一塊連續的內存空間。
單線程,需要暫停應用並耗時較長。

所有的串行GC處理都只是單線程處理,那麼在進行處理的時候都必須暫停操作。

老年代-並行GC:
這裏寫圖片描述

劃分多個區域,一個線程一個區域。多個線程並行將多個存活對象整理在一起,並將所有被回收的對象的空間整合爲一體。
與串行的處理操作相比,整體的操作只是多了一個多線程的支持,但是這樣的暫停時間就會減少。但是由於老年代的空間一般比較大,所以在掃描和標記存活對象上需要花費較長時間。

老年代-並行CMS GC

這裏寫圖片描述

這裏寫圖片描述

優缺點:只有在第一次和重新標記階段纔會暫停整個應用,這樣對應用程序所帶來的影響非常小,缺點是併發標記與回收線程會爭搶CPU資源,並且容易產生內存碎片。

內存越大,可能產生的垃圾越多,掃描的時間越長,成正比操作。儘量減少無用內存的產生。

- 垃圾回收策略配置

常用的GC策略:
這裏寫圖片描述

對於JVM而言,本身有兩種的運行模式:單機版客戶端程序(client),服務器程序(server)–主要使用

參數配置:
這裏寫圖片描述

參數
這裏寫圖片描述

如果想確認使用的GC的處理,首先需要知道當前主機上可以支持的處理進程數量。(比如32進程)
範例:取得可用的進程數量。

這裏寫圖片描述

範例:觀察默認的GC處理模式:

這裏寫圖片描述
PSYoung:
此時默認狀態下,年輕代使用的是:並行回收GC(Parallel Scavenge)來進行垃圾釋放。

這裏寫圖片描述

ParOldGen
而老年代的回收使用的是“ParOldGen”,採用的是並行GC完成的老年代處理。

JVM根據電腦情況自動選擇的GC策略,大部分情況,沒必要去調整GC策略。

範例:使用串行GC:

這裏寫圖片描述

範例:使用並行GC:

這裏寫圖片描述

包含警告:
這裏寫圖片描述

這裏寫圖片描述

範例使用CMS處理:
只針對與並行的GC 老年代有效:
這裏寫圖片描述

這裏寫圖片描述

這個時候通過上面的輸出可以看到CMS會經歷如下幾個步驟:
1.“CMS-concurrent-mark-start” : CMS標記開始
2.“CMS-concurrent-mark”:表示開始進行標記,進入到了STW(暫停)狀態。
3.“CMS-concurrent-preclean-satrt”:表示預清理開始。
4.“CMS-concurrent-sweep-start”:開始進行無用對象清理

CMS的處理適當性能會好一點,但是這所有的GC策略都是現在正在常用的策略。不過似乎都有缺陷。

實際開發之中對於GC的策略不建議手工修改,默認的一般比較好用。當然只是侷限於傳統的GC清理處理過程。

- G1收集器

  • G1收集器簡介:
    很多的GC收集策略雖然提供了,但是依然會發現這些策略總會有那麼一點點的不合理,造成所有不合理的本質只有一點:內存一大,什麼都廢了。而且現在大內存的主機,多CPU的主機越來越多了。所以java從十多年前就已經意識到了此類問題,於是偷偷摸摸的提出了一個新的垃圾收集器(沒大用起來呢)。這個收集器就是G1收集器。

這裏寫圖片描述

雖然G1收集器是十多年前提出的概念,但是真正的出現是在jdk1.7的時候出來的(Oracle發佈的)。有很多javaBUG從最初到到1.6都有,但是被Oracle收購後,jdk不斷更新。
此垃圾收集器G1主要應用在多CPU以及大內存的服務器環境下。極大減少了垃圾收集的停頓時間,以提升服務器的性能。
引入目的:爲了將來的某一個時間可以替換掉CMS(ConcurrentMarkSweep)收集器。但是這個剛剛出現不久,還沒有被默認支持,需手動開啓。

對java服務器而言,如何去選擇一個合適的配置?默認情況下,java會爲每一個線程分配1M的內存空間,那麼如果你現在的電腦有32G的內存空間,最大可分配30G內存,那麼理論上可以處理(30*1024=30720)個用戶請求,真要做到這麼高的訪問量(每秒)上,不崩潰也快死機了。
因爲網絡設備、I/O設備也會佔用內存。所以一般的服務器處理5000-10000基本上也就夠了。(動態搭建服務器)
理論上30g不現實,因爲佔用太高。
一臺服務器不可能內存太大。但是可以做虛擬,虛擬是個子電腦,之後再做集羣。
ConcurrentHashMap:一個操作鎖定,其它操作正常訪問
HashTable:整個表給鎖定。

G1區域劃分:
這裏寫圖片描述
在JVM啓動時會自動設置這些子區域(Region)的大小,區域大小範圍:1MB - 32MB,最多可以設置2048個區域,及支持的最大內存爲32MB*2048 = 65536M 即64G。
JVM運行,內存越大不一定效率越高,性能越好。

此時按照G1的實現方案相當於現在將所有的子內存區域合併在了一起,也不再進行任何的區分。這樣就相當於所有的內存的區域都可以按照統一的方式進行規劃處理。而G1的最大特點就是避免了全內存掃描。所以G1將直接帶來性能的提升。

- *G1回收策略

現在的發展:簡化,太細緻反而是個負擔。
細緻複雜配置—簡化配置。

這裏寫圖片描述

這裏寫圖片描述

這裏寫圖片描述

這個回收過程只針對一個內存區域。多個區域之間互不干擾和影響。

這裏寫圖片描述

這裏寫圖片描述

這裏寫圖片描述

這裏寫圖片描述

這裏寫圖片描述

在整個G1進行標記和清理的時候是按照區域完成的,這樣不影響其他區域的執行,除此之外,使用的形式和之前的CMS都是非常類似的操作方式。

G1相關處理參數:
如果使用G1收集器,則必須由用戶自己來進行參數的指定,有如下的可用參數:
這裏寫圖片描述

範例:使用G1收集器

這裏寫圖片描述
整個流程明顯發生了改變。

這裏寫圖片描述

這裏寫圖片描述

G1垃圾收集的處理性能一定要比傳統的GC垃圾回收處理要高,但是G1的垃圾收集器需要用戶來手動啓動指派,而非默認支持的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章