JVM自動內存管理機制

Jvm的自動內存管理機制,主要包括內存回收和內存分配。java

內存回收算法

對於內存回收機制主要圍繞「哪些內存須要回收?」、「何時回收?」、「如何回收?」這三個問題來展開。安全

1、哪些內存須要回收?

不可能再被任何途徑使用的對象須要被回收。多線程

如何判斷一個對象是否還能夠再被引用?併發

這裏有兩個方法能夠作到:(1 引用計數法  (2 可達性分析佈局

引用計數法:給對象維護一個計數器,每次被引用計數器的值+1,每次引用被釋放,計數器的值-1,當計數器的值爲0時,認爲它不可能再被引用了。spa

可達性分析:從GCRoots向下搜索,走過的路徑爲引用鏈,當一個對象到GCRoots沒有任何引用鏈相連則證實對象不可用。線程

因爲引用計數法很難解決對象循環引用的場景,所以通常都使用可達性分析來判斷一個對象是否存活。對象

 

2、何時回收?

2.1    新生代的回收時機

新的對象須要在Eden區申請內存,但Eden區沒有足夠的連續的空間分配給對象會觸發一次minor GC內存

2.2    老年代的回收時機

重新生代過來的對象須要在老年代申請空間,但老年代沒有足夠的連續的空間來分配,會觸發一次major GC。

HotSpot VM 老年代給新生代作空間擔保時,若老年代連續可用空間小於歷次晉升到老年代對象的平均大小,觸發一次major GC。

 

3、如何回收?

3.1    回收算法

  標記-清除(Mark-Sweep):標記存活的對象,把剩下的對象清除掉。問題:會產生大量的空間碎片。

  複製(Copying):把內存分爲兩塊相同大小的空間,一塊使用稱爲From,一塊保留稱爲To,回收時把From裏面存活的對象複製到To中,複製完成後清除To中的所有內容。解決了空間碎片的問題,但空間利                                  用率過低。HotSpot利用新生代對象存活時間短,一次GC大部分對象會被回收,小部分對象須要複製這一特色,將新生代分爲一塊Eden區和兩塊大小相同的Survior區,每次使用                                            Eden+Survivor空閒一塊Survivor,經過參數SuriviorRatio來控制Eden區和Survior的比例從而提高空間利用率。

  標記-整理(Mark-Compact):標記存活的對象,並讓它們向一端移動,清除移動邊界之外的對象。能夠解決空間碎片的問題。

3.2 垃圾回收器

HotSpot虛擬機的垃圾回收器:Serial、ParNew、Parallel Scavenge、CMS、Serial Old、Parallel Old、G1。

 

Young Generation

 

Serial收集器:單線程,收集時暫停全部工做線程,直到它收集完成。

ParNew收集器:多線程,使用多條線程進行垃圾回收,一樣須要暫停全部的工做線程

Parallel Scavenge收集器:多線程,和ParNew的區別在於,這個收集器關注的是吞吐量

吞吐量 = 程序執行時間/程序執行時間+垃圾回收時間,這個收集器提供能夠精準控制吞吐量的參數:

-XX:MaxGCPauseMillis最大垃圾回收停頓時間

-XX:GCTimeRatio吞吐量大小

-XX:+UseAdaptiveSizePolicy開啓自適應調節策略,自動調節各個參數來提供最適合的停頓時間或最大的吞吐量。

 

 

Young Generation通常使用的是複製算法。

Serial、ParNew能夠和CMS搭配使用,但Parallel Scavenge不行。

 

Tenured Generation

 

Serial Old收集器:Serial收集器的老年代版本,單線程,使用標記整理算法,能夠和Parallel Scavenge搭配使用,也能夠做爲CMS的後備方案

Parallel Old收集器:Parallel Scavenge的老年代版本,多線程,使用標記整理算法, 能夠和Parallel Scavenge搭配使用實現真正的吞吐量優先GC。

CMS(Concurrent Mark Sweep)收集器:併發收集,以獲取最短的回收停頓時間爲目標的收集器,使用標記清除算法(爲何不用標記-整理算法,整理時須要控制併發,停掉工做線程,會延長stop-the-world的時間,和獲取最短的回收停頓時間爲目標的理念相沖突)。

CMS回收的過程:1、初始標記 2、併發標記 3、從新標記 4、併發清除

初始標記:stop-the-world標記GCRoots能夠直接關聯的對象

併發標記:完成餘下的GCRoots Tracing標記(用戶線程和GC線程併發執行)

從新標記:stop-the-world修正併發標記期間因用戶程序繼續運做而致使標記產生變更的那一部分對象的標記記錄

併發清除:執行清除操做,和用戶線程併發執行

 

CMS回收器的缺陷:

1、對cpu的資源敏感,因爲GC過程有兩個階段是併發進行的,會搶佔cpu資源,下降系統的吞吐量。

2、浮動垃圾,在併發清除階段,也會產生不可達對象,這些對象只能等到下次GC時才能被回收。因爲浮動垃圾的存在,CMS不能等到內存被填滿才進行垃圾回收,必須預留足夠的空間,經過-XX:CMSInitiatingOccupancyFraction參數設置觸發CMS回收的百分比閾值。當CMS GC期間預留的內存沒法知足程序需求時會出現Concurrent Mode Failure 失敗,會臨時啓用後備方案使用Seria Old進行老年代GC,會出現較長的stop-the-world停頓。

3、標記-清除會產生大量的空間碎片,若老年代還有不少空間,但沒法找到足夠大的連續空間來分配當前對象會提早出發full GC

–XX:+UseCMSCompactAtFullCollection參數設置在CMS要進行Full GC是開啓內存碎片的合併整理過程,整理過程不能併發,須要stop-the-world

-XX:CMSFullGCsBeforeCompaction = ?,設置執行多少次不壓縮的Full GC後接着來一次帶壓縮的Full GC

 

G1收集器:併發收集器,追求更小的stop-the-world時間。

G1收集器的特色:

1)javad堆的內存佈局.將整個java堆分爲多個大小相等的獨立區域(Region),雖然還保留了新生代和老年代的概念,但新生代和老年代不將再是物理隔離的,它們都是部分Region的集合.

2)分代收集,G1收集器能夠獨自管理整個GC堆,而且能夠根據對象的存活時間採用不一樣的方式收集。

3)空間整合,G1收集器從總體來看是基於標記-整理算法來實現,局部來看(兩個Region之間)是基於複製算法來實現的,這就意味着G1收集器能夠規避掉CMS算法的空間碎片的問題

4)可預測的停頓。G1相對於CMS收集器的另外一個優點是能夠創建一個可預測的停頓時間模型。經過-XX:MaxGCPauseMillis=? 來設置最大GC時間。

5)化整爲零的GC思想.G1會跟蹤各個Region裏面的垃圾堆積的價值大小(回收空間、回收時間)並在後臺維護一個優先級列表,優先回收優先級高的Region,而不是毫無計劃的在堆上進行全區域垃圾回收,這樣能夠保證G1收集器能夠在有限的時間能夠得到更可能高的收集效率。

G1收集器在進行可達性分析時爲了不全堆掃描,在Region中會記錄一個Remember Set來保存哪些對象引用過這個Region

新生代收集:stop-the-world,Eden和Survivor區存活的對象被複制到另外一塊Survivor區,若是年齡達到閾值或Survivor區的空間不足會直接分配到老年代,並清空已經處理過的Eden和Survivor區。

老年代收集:初始標記、併發標記、最終標記、篩選回收(最後也會把存活對象複製到另外一個Region中,從而避免了空間碎片的問題)

 

爲何選擇Serial Old 做爲CMS的後備方案而不選擇多線程並行的Parallel Old,緣由在於Serial Old能夠和年輕代的三種搭配使用,而Parallel Old只能和Parallel Scavenge搭配使用。

並行和併發:這裏說的並行是多線程進行GC,但暫停工做線程,併發說的是GC和工做線程一塊兒多線程執行,也就是說,串行和並行都須要stop-the-world,併發不須要stop-the-world。

 

內存分配

對象的內存分配主要在堆上進行,對於新對象主要分配在Eden區,少數狀況也會直接分配到老年代。

1.1        對象優先在Eden去分配

 新對象進入Eden區,當Eden區容量不足時,進行一次minior GC。GC時,當Eden區+Survivor From區複製到Surivivor To區,Surivivor To區容量不足時,Eden區+Survivor From區的對象直接進入老年代。

1.2        大對象直接進入老年代

-XX:PretenureSizeThreshold參數設置對象大小閾值,大於這個值的對象直接進入老年代

1.3        長期存活的對象直接進入老年代

Survivor區中的對象每熬過一次minor GC年齡就增長1歲,-XX:MaxTenuringThreshold設置年齡閾值,達到閾值的對象直接進入老年代

1.4        年齡相同對象所佔空間超過Survivor區的一半,則大於等於這個年齡的對象直接進入老年代

1.5        空間分配擔保

當新生代採用Eden、Survivor式的複製算法時須要老年代對其進行內存擔保(由於minior GC時,若是Survivor區的容量不足以接納Survivor區+Eden區的對象,則他們將所有進入老年代)

Minior GC以前先檢查是否能夠確保這次GC的安全,

先檢查老年代的最大可用連續空間是否大於新生代全部對象的總空間,若是成立則能夠確保這次monior GC是安全的,若是不成立,檢查老年代最大可用連續空間是否大於歷次晉升到老年代對象的平均大小,若是大於嘗試一次minior GC, 不然進行一次Full GC.

 

HotSpot VM經常使用參數表:

-XX:設置  -XX:+參數 (開啓?功能)  -XX:-參數(關閉?功能)  -XX:參數 = ?(設置參數的值)

-Xms? 設置堆的初始大小
-Xmx? 設置堆的最大值
-Xmn? 設置新生代的大小

-Xss? 設置每一個線程的棧的大小
-XX:SurvivorRatio=? 設置Eden區和Survior區的大小比值-XX:CMSInitiatingOccupancyFraction=?設置CMS收集器在老年代空間閾值,達到這個閾值進行垃圾回收-XX:MaxTenuringThreshold=?晉升到老年代的對象年齡閾值
相關文章
相關標籤/搜索