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的垃圾收集器需要使用者來手動啟動指派,而非預設支援的。