天天看點

java 記憶體回收參數_JVM記憶體模型及垃圾回收的研究總結

Java記憶體模型

總的來說就分為兩個區域,堆記憶體(Heap)和非堆記憶體(No-Heap),非堆記憶體又稱為永久代(Permanent),永久的意思其實是針對于垃圾回收器來說的,表示這部分内容不需要回收。在新的JDK8中,這部分的名稱已經不叫Permanent了,改成更好了解的Metaspace了。這部分是用來存儲JVM工作的相關資料的,比如Load下來的class定義、靜态變量、用于排程的方法和線程棧。

java 記憶體回收參數_JVM記憶體模型及垃圾回收的研究總結

為什麼要分為這兩個區域呢?其實也是為了垃圾回收器用的,堆記憶體用來存儲Java對象執行個體,是以這部分才需要進行回收。而非堆記憶體是JVM自己的工作空間,屬于JVM實作的一部分,JVM在實作的時候已經自己實作了記憶體回收。

值得注意的是,在GC日志中,你會發現PSPermGen也在其中:

[GC-- [PSYoungGen: 569856K->569856K(617472K)] 773089K->928306K(976896K), 0.3285123 secs] [Times: user=0.66 sys=0.08, real=0.33secs]

[Full GC [PSYoungGen: 569856K->0K(617472K)] [ParOldGen: 358450K->359349K(499712K)] 928306K->359349K(1117184K) [PSPermGen: 64652K->64650K(131072K)], 1.4693823 secs] [Times: user=4.09 sys=0.02, real=1.47secs]

[Full GC [PSYoungGen: 569856K->0K(617472K)] [ParOldGen: 359349K->488638K(672768K)] 929205K->488638K(1290240K) [PSPermGen: 65041K->65041K(131072K)], 2.4092196 secs] [Times: user=6.75 sys=0.11, real=2.41 secs]

意思是No-Heap(永久代)也需要垃圾回收?

确實是這樣的,因為在永久代中還存儲着ClassLoader、Class的元資訊(Metadata)、指向Heap區域對象的指針以及字元串池(Internal String)。這些資料其實也需要垃圾回收。

這樣看來,把記憶體區域劃分為年輕代(Young Gen)、老年代(Old Gen)和永久代(Permanent Gen)其實是有道理的,雖然老年代的資料不會提升到永久代中。但是這三個區域的資料都是需要垃圾回收的。

Heap(堆記憶體)

堆記憶體是垃圾回收器工作的地方,堆記憶體又分為Eden和兩個大小一樣的Survivor區,即From和To。

最開始的對象都會存儲在Eden中(如果有些大對象無法存入到年輕代,則會直接存入老年代),然後經過Minor GC之後會被提升到Survivor區,然後再提升到老年代。

java 記憶體回收參數_JVM記憶體模型及垃圾回收的研究總結

Stack(棧記憶體)

Thread Stack 用來存放棧資訊,每個線程棧資訊裡各自有自己的方法棧(包括本地方法棧),在方法棧的每一幀裡存儲着方法調用的相關資訊,比如參數值、局部變量、傳回值等。

Program Counter:記錄着目前語句執行到哪兒了。

下圖中,其實Stack可以歸并到No-Heap中。

java 記憶體回收參數_JVM記憶體模型及垃圾回收的研究總結

垃圾回關注的名額

吞吐量

定義:使用者代碼執行時間  / ( 使用者代碼執行時間 + 垃圾回收時間)

越高越好,越高表示執行垃圾回收時間越少。

暫停時間

回收時可能需要暫停使用者線程,暫停時間越短越好。

執行頻率

機關時間垃圾回收執行的次數。

堆記憶體大小

比如G1回收器就要去比較大的Heap記憶體。

敏感度(Promptness)

對象變成垃圾到被回收的時間,時間越短表示回收器越敏感。

垃圾回收類型

串行搜集器(Serial)

年輕代(Young Gen)回收

java 記憶體回收參數_JVM記憶體模型及垃圾回收的研究總結

老年代(Old Gen)回收

來年代的回收很簡單,步驟是“标記-清除-壓縮”:

java 記憶體回收參數_JVM記憶體模型及垃圾回收的研究總結

串行回收器的使用場景

一般引用于不要求“低暫停”的client模式。這裡參考server和client的差別。j2se5的client模式下預設使用串行回收器進行垃圾回收。

使用串行回收器的參數:-XX:+UseSerialGC

并行回收器(Paraller)

并行回收器可以利用多個CPU進行并行的垃圾回收。(在多個CPU場景下,使用Serial回收器時,其實隻有一個CPU在工作,其他CPU相當于閑置狀态)

并行回收器在年輕地啊和老年代進行垃圾回收的操作是一樣的,都是标記、轉移、壓縮,隻是它啟用了多個CPU并發執行。串行和并行都需要stop-the-world。

java 記憶體回收參數_JVM記憶體模型及垃圾回收的研究總結

并行回收器的使用場景

應用于多CPU場景下,但是沒有太大的暫停時間要求,因為還是有可能會發生長時間的老年代垃圾回收。

适用于批處理、賬單、财務、科學計算等場景。

j2se5的server模式下預設使用該回收器。

使用并行回收器的參數:-XX:+UseParallelGC

ParNew

這是一個加強版的Parallel回收器。它可以與下面提到的CMS回收器進行配合。

并行壓縮回收器(Parallel Compacting)

年輕代使用并行回收器一樣的算法(多CPU并行回收)。(stop-the-world)

-XX:+UseParallelOldGC.

對于老年代,回收過程分為三個階段

并行标記(Marking)

标記出每個區域的活動資料。标記動作其實是和使用者線程一起跑的。

計算總結(Summary)

計算各個區域的稠密程度,得出移動資料的方案。(稀疏的往稠密位置移動,壓縮速度肯定比相反方向要快)

壓縮(Compaction)

把資料移動到一端,保證另外一端空白。

并行壓縮回收器的使用場景

多CPU,它相對于并行回收器感覺沒有什麼差別(誰知道嗎???),因為在官方文檔中是這樣說的:

java 記憶體回收參數_JVM記憶體模型及垃圾回收的研究總結

使用該回收器的參數:-XX:-UseParallelOldGC

并發标記清理回收器(Concurrent Mark-Sweep (CMS))

低延遲的回收器。

一般而言,年輕代的回收不會有太大的暫停。而老年代的回收不會經常執行,是以老年代的回收暫停時間長一點兒也沒事。CMS的回收步驟如下:

年輕代還是使用并發回收器(Parallel)。

對于老年代:

初始标記(init mark):單線程stop-the-world執行,短暫停,确定出直接和程式關聯的活動對象集合。

并發标記(concurrent marking):根據上一步标記出來的集合,并發找出與集合中元素關聯的其他活動對象。這一步的執行是和使用者線程并發執行的。

重新标記(remark):由于使用者線程也在運作,是以上一步标記出來的對象還有可能又參數了垃圾,是以這裡再次stop-the-world,重新找出活動資料。這一步對現場并發執行。很容易了解,這裡的stop-the-world也是非常短的。

清理(sweep):根據上一步标記結果,清理記憶體。

java 記憶體回收參數_JVM記憶體模型及垃圾回收的研究總結

從CMS的執行步驟可以看出,它的核心思想其實就是把事情分成多個步驟來做,不要一次把事情做完,且盡量和使用者線程一起執行,進而實作對使用者線程的低延遲。

CMS回收器使用場景

任何需要低延遲的應用。甚至在單CPU上都運作良好。

使用CMS回收器參數:-XX:+UseConcMarkSweepGC

G1(Gargage First)回收器

G1回收器是用于server模式下,多處理器、大記憶體的環境。其目标是高吞吐量、高可用性。在JDK7 update4以後的版本中都支援。長期計劃中G1是用來代替CMS回收器的。

G1不像其他回收器那樣,把記憶體明确地劃分為三個固定大小的區域。而是把heap看成一個整體。

java 記憶體回收參數_JVM記憶體模型及垃圾回收的研究總結

更多細節詳見參考連接配接。

垃圾收集器參數總結

收集器設定:

-XX:+UseSerialGC:年輕串行(Serial),老年串行(Serial Old)

-XX:+UseParNewGC:年輕并行(ParNew),老年串行(Serial Old)

-XX:+UseConcMarkSweepGC:年輕并行(ParNew),老年串行(CMS),備份(Serial Old)

-XX:+UseParallelGC:年輕并行吞吐(Parallel Scavenge),老年串行(Serial Old)

-XX:+UseParalledlOldGC:年輕并行吞吐(Parallel Scavenge),老年并行吞吐(Parallel Old)

收集器參數:

-XX:ParallelGCThreads=n:設定并行收集器收集時使用的CPU數。并行收集線程數。

-XX:MaxGCPauseMillis=n:設定并行收集最大暫停時間

-XX:GCTimeRatio=n:設定垃圾回收時間占程式運作時間的百分比。公式為1/(1+n)

-XX:+CMSIncrementalMode:設定為增量模式。适用于單CPU情況。

-XX:ParallelGCThreads=n:設定并發收集器年輕代收集方式為并行收集時,使用的CPU數。并行收集線程數。

參考: