JVM結構、GC工做機制詳解

轉載於:https://blog.csdn.net/tonytfjing/article/details/44278233 java

1、JVM結構linux

根據《java虛擬機規範》規定,JVM的基本結構通常以下圖所示:web




從左圖可知,JVM主要包括四個部分:算法

1.類加載器(ClassLoader):在JVM啓動時或者在類運行時將須要的class加載到JVM中。(右圖表示了從java源文件到JVM的整個過程,可配合理解。 關於類的加載機制,能夠參考http://blog.csdn.net/tonytfjing/article/details/47212291)數組


2.執行引擎:負責執行class文件中包含的字節碼指令(執行引擎的工做機制,這裏也不細說了,這裏主要介紹JVM結構);tomcat


3.內存區(也叫運行時數據區):是在JVM運行的時候操做所分配的內存區。運行時內存區主要能夠劃分爲5個區域,如圖:服務器


方法區(Method Area):用於存儲類結構信息的地方,包括常量池、靜態變量、構造函數等。雖然JVM規範把方法區描述爲堆的一個邏輯部分, 但它卻有個別名non-heap(非堆),因此你們不要搞混淆了。方法區還包含一個運行時常量池。多線程

java堆(Heap):存儲java實例或者對象的地方。這塊是GC的主要區域(後面解釋)。從存儲的內容咱們能夠很容易知道,方法區和堆是被全部java線程共享的。併發

java棧(Stack):java棧老是和線程關聯在一塊兒,每當建立一個線程時,JVM就會爲這個線程建立一個對應的java棧。在這個java棧中又會包含多個棧幀,每運行一個方法就建立一個棧幀,用於存儲局部變量表、操做棧、方法返回值等。每個方法從調用直至執行完成的過程,就對應一個棧幀在java棧中入棧到出棧的過程。因此java棧是現成私有的。app

程序計數器(PC Register):用於保存當前線程執行的內存地址。因爲JVM程序是多線程執行的(線程輪流切換),因此爲了保證線程切換回來後,還能恢復到原先狀態,就須要一個獨立的計數器,記錄以前中斷的地方,可見程序計數器也是線程私有的。

本地方法棧(Native Method Stack):和java棧的做用差很少,只不過是爲JVM使用到的native方法服務的。


4.本地方法接口:主要是調用C或C++實現的本地方法及返回結果。



2、內存分配

我以爲了解垃圾回收以前,得先了解JVM是怎麼分配內存的,而後識別哪些內存是垃圾須要回收,最後纔是用什麼方式回收。


Java的內存分配原理與C/C++不一樣,C/C++每次申請內存時都要malloc進行系統調用,而系統調用發生在內核空間,每次都要中斷進行切換,這須要必定的開銷,而Java虛擬機是先一次性分配一塊較大的空間,而後每次new時都在該空間上進行分配和釋放,減小了系統調用的次數,節省了必定的開銷,這有點相似於內存池的概念;二是有了這塊空間事後,如何進行分配和回收就跟GC機制有關了。


java通常內存申請有兩種:靜態內存和動態內存。很容易理解,編譯時就可以肯定的內存就是靜態內存,即內存是固定的,系統一次性分配,好比int類型變量;動態內存分配就是在程序執行時才知道要分配的存儲空間大小,好比java對象的內存空間。根據上面咱們知道,java棧、程序計數器、本地方法棧都是線程私有的,線程生就生,線程滅就滅,棧中的棧幀隨着方法的結束也會撤銷,內存天然就跟着回收了。因此這幾個區域的內存分配與回收是肯定的,咱們不須要管的。可是java堆和方法區則不同,咱們只有在程序運行期間才知道會建立哪些對象,因此這部份內存的分配和回收都是動態的。通常咱們所說的垃圾回收也是針對的這一部分。


總之Stack的內存管理是順序分配的,並且定長,不存在內存回收問題;而Heap 則是爲java對象的實例隨機分配內存,不定長度,因此存在內存分配和回收的問題;


3、垃圾檢測、回收算法

垃圾收集器通常必須完成兩件事:檢測出垃圾;回收垃圾。怎麼檢測出垃圾?通常有如下幾種方法:


引用計數法:給一個對象添加引用計數器,每當有個地方引用它,計數器就加1;引用失效就減1。


好了,問題來了,若是我有兩個對象A和B,互相引用,除此以外,沒有其餘任何對象引用它們,實際上這兩個對象已經沒法訪問,便是咱們說的垃圾對象。可是互相引用,計數不爲0,致使沒法回收,因此還有另外一種方法:


可達性分析算法:以根集對象爲起始點進行搜索,若是有對象不可達的話,便是垃圾對象。這裏的根集通常包括java棧中引用的對象、方法區常良池中引用的對象


本地方法中引用的對象等。


總之,JVM在作垃圾回收的時候,會檢查堆中的全部對象是否會被這些根集對象引用,不可以被引用的對象就會被垃圾收集器回收。通常回收算法也有以下幾種:


1.標記-清除(Mark-sweep)

算法和名字同樣,分爲兩個階段:標記和清除。標記全部須要回收的對象,而後統一回收。這是最基礎的算法,後續的收集算法都是基於這個算法擴展的。

不足:效率低;標記清除以後會產生大量碎片。效果圖以下:



2.複製(Copying)

此算法把內存空間劃爲兩個相等的區域,每次只使用其中一個區域。垃圾回收時,遍歷當前使用區域,把正在使用中的對象複製到另一個區域中。此算法每次只處理正在使用中的對象,所以複製成本比較小,同時複製過去之後還能進行相應的內存整理,不會出現「碎片」問題。固然,此算法的缺點也是很明顯的,就是須要兩倍內存空間。效果圖以下:


3.標記-整理(Mark-Compact)

此算法結合了「標記-清除」和「複製」兩個算法的優勢。也是分兩階段,第一階段從根節點開始標記全部被引用對象,第二階段遍歷整個堆,把清除未標記對象而且把存活對象「壓縮」到堆的其中一塊,按順序排放。此算法避免了「標記-清除」的碎片問題,同時也避免了「複製」算法的空間問題。效果圖以下:


(1,2,3 圖文摘自 http://pengjiaheng.iteye.com/blog/520228,感謝原做者。)


4.分代收集算法

這是當前商業虛擬機經常使用的垃圾收集算法。分代的垃圾回收策略,是基於這樣一個事實:不一樣的對象的生命週期是不同的。所以,不一樣生命週期的對象能夠採起不一樣的收集方式,以便提升回收效率。


爲何要運用分代垃圾回收策略?在java程序運行的過程當中,會產生大量的對象,因每一個對象所能承擔的職責不一樣所具備的功能不一樣因此也有着不同的生命週期,有的對象生命週期較長,好比Http請求中的Session對象,線程,Socket鏈接等;有的對象生命週期較短,好比String對象,因爲其不變類的特性,有的在使用一次後便可回收。試想,在不進行對象存活時間區分的狀況下,每次垃圾回收都是對整個堆空間進行回收,那麼消耗的時間相對會很長,並且對於存活時間較長的對象進行的掃描工做等都是徒勞。所以就須要引入分治的思想,所謂分治的思想就是因地制宜,將對象進行代的劃分,把不一樣生命週期的對象放在不一樣的代上使用不一樣的垃圾回收方式。


如何劃分?將對象按其生命週期的不一樣劃分紅:年輕代(Young Generation)、年老代(Old Generation)、持久代(Permanent Generation)。其中持久代主要存放的是類信息,因此與java對象的回收關係不大,與回收息息相關的是年輕代和年老代。這裏有個比喻很形象


「假設你是一個普通的 Java 對象,你出生在 Eden 區,在 Eden 區有許多和你差很少的小兄弟、×××妹,能夠把 Eden 區當成幼兒園,在這個幼兒園裏你們玩了很長時間。Eden 區不能無休止地放大家在裏面,因此當年紀稍大,你就要被送到學校去上學,這裏假設從小學到高中都稱爲 Survivor 區。開始的時候你在 Survivor 區裏面劃分出來的的「From」區,讀到高年級了,就進了 Survivor 區的「To」區,中間因爲學習成績不穩定,還常常來回折騰。直到你 18 歲的時候,高中畢業了,該去社會上闖闖了。因而你就去了年老代,年老代裏面人也不少。在年老代裏,你生活了 20 年 (每次 GC 加一歲),最後壽終正寢,被 GC 回收。有一點沒有提,你在年老代遇到了一個同窗,他的名字叫愛德華 (慕光之城裏的帥哥吸血鬼),他以及他的家族永遠不會死,那麼他們就生活在永生代。」


具體區域能夠經過VisualVM中的VisaulGC插件查看,如圖(openjdk 1.7):



年輕代:是全部新對象產生的地方。年輕代被分爲3個部分——Enden區和兩個Survivor區(From和to)當Eden區被對象填滿時,就會執行Minor GC。並把全部存活下來的對象轉移到其中一個survivor區(假設爲from區)。Minor GC一樣會檢查存活下來的對象,並把它們轉移到另外一個survivor區(假設爲to區)。這樣在一段時間內,總會有一個空的survivor區。通過屢次GC週期後,仍然存活下來的對象會被轉移到年老代內存空間。一般這是在年輕代有資格提高到年老代前經過設定年齡閾值來完成的。須要注意,Survivor的兩個區是對稱的,沒前後關係,from和to是相對的。


年老代:在年輕代中經歷了N次回收後仍然沒有被清除的對象,就會被放到年老代中,能夠說他們都是久經沙場而不亡的一代,都是生命週期較長的對象。對於年老代和永久代,就不能再採用像年輕代中那樣搬移騰挪的回收算法,由於那些對於這些回收戰場上的老兵來講是小兒科。一般會在老年代內存被佔滿時將會觸發Full GC,回收整個堆內存。


持久代:用於存放靜態文件,好比java類、方法等。持久代對垃圾回收沒有顯著的影響。 


分代回收的效果圖以下:



我這裏之因此最後講分代,是由於分代裏涉及了前面幾種算法。年輕代:涉及了複製算法;年老代:涉及了「標記-整理(Mark-Sweep)」的算法。



4、垃圾收集器

垃圾收集算法是內存回收的方法論,而實現這些方法論的則是垃圾收集器。不一樣廠商不一樣版本JVM所提供的垃圾收集器可能不一樣,這裏參照《深刻理解Java虛擬機》說的是JDK1.7版本Hotspot虛擬機,關於垃圾收集器有篇博文總結的不錯,我就不說了,詳見:http://blog.csdn.net/java2000_wl/article/details/8030172



GC 命令

一、jstat -gccause pid

監視Java堆情況,包括Eden區、兩個survivor區、老年代、永久代等的容量、已用空間、GC時間合計等信息、致使上一次GC產生的緣由


eg.

jstat -gccause 28061

S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT    LGCC                 GCC

36.15   0.00  56.61  30.54  91.83  87.63    944  119.607     5    5.926  125.532 Allocation Failure   No GC


S0:年輕代中第一個survivor(倖存區)已使用的佔當前容量百分比

S1:年輕代中第二個survivor(倖存區)已使用的佔當前容量百分比

E:年輕代中Eden(伊甸園)已使用的佔當前容量百分比

O:old代已使用的佔當前容量百分比

M:元空間(Metaspace)已使用的佔當前容量百分比,相似1.8以前的永久代(PermGen)

CCS:CCS表示的是Metaspace的使用率,也就是CCSU/CCSC算出來的

YGC:從應用程序啓動到採樣時年輕代中gc次數

YGCT:從應用程序啓動到採樣時年輕代中gc所用時間(s)

FGC:從應用程序啓動到採樣時old代(全gc)gc次數

FGCT:從應用程序啓動到採樣時old代(全gc)gc所用時間(s)

GCT:從應用程序啓動到採樣時gc用的總時間(s)

LGCC:最近一次full gc的緣由

GCC:


二、jmap -heap pid

顯示Java堆詳細信息,如使用哪一種回收器、參數配置、分代情況等


eg.

jmap -heap 28061


Attaching to process ID 28061, please wait...

Debugger attached successfully.

Server compiler detected.

JVM version is 25.91-b14

using thread-local object allocation.

Parallel GC with 30 thread(s)


Heap Configuration:

MinHeapFreeRatio         = 0

MaxHeapFreeRatio         = 100

MaxHeapSize              = 23622320128 (22528.0MB)

NewSize                  = 7516192768 (7168.0MB)

MaxNewSize               = 7516192768 (7168.0MB)

OldSize                  = 16106127360 (15360.0MB)

NewRatio                 = 2

SurvivorRatio            = 8

MetaspaceSize            = 21807104 (20.796875MB)

CompressedClassSpaceSize = 1073741824 (1024.0MB)

MaxMetaspaceSize         = 17592186044415 MB

G1HeapRegionSize         = 0 (0.0MB)


Heap Usage:

PS Young Generation

Eden Space:


capacity = 7132413952 (6802.0MB)

used     = 1967181000 (1876.0499954223633MB)

free     = 5165232952 (4925.950004577637MB)

27.580858503710132% used


From Space:

capacity = 190840832 (182.0MB)

used     = 29685552 (28.310348510742188MB)

free     = 161155280 (153.6896514892578MB)

15.555136544363839% used


To Space:

capacity = 191365120 (182.5MB)

used     = 0 (0.0MB)

free     = 191365120 (182.5MB)

0.0% used


PS Old Generation

capacity = 16106127360 (15360.0MB)

used     = 5054486720 (4820.334167480469MB)

free     = 11051640640 (10539.665832519531MB)

31.382383902867634% used

74399 interned Strings occupying 7907472 bytes.


三、jmap -dump:[live,]format=b,file=<filename> pid

生成Java堆轉儲快照。格式爲:-dump:[live,]format=b,file=<filename>,其中live子

參數說明是否只dump出存活的對象

生成dump文件跟當前jvm內存大小有關,可能生成的文件會很大。


四、jmap -histo pid 顯示堆中對象統計信息,包括類、實例數據、合計容量。

eg.

jmap -histo 28061

num     #instances         #bytes  class name

----------------------------------------------

1:      11410026     1362675080  [C

2:       2219154     1103383864  [B

3:      21667070      866682800  java.util.LinkedHashMap$Entry

4:      12121603      387891296  java.util.Hashtable$Entry

5:       5064770      283627120  java.security.Provider$Service

6:      10239384      245745216  java.security.Provider$ServiceKey

7:      10129191      243100584  java.lang.String

8:        856460      242869960  [Ljava.util.HashMap$Node;

9:        859192      236504032  [I

10:       3646059      145784816  [Ljava.lang.Object;

11:         20705       88713496  [Ljava.util.Hashtable$Entry;

12:       2650951       84830432  java.lang.StackTraceElement

13:       2806632       67359168  java.util.ArrayList

14:       1980684       63381888  java.util.HashMap$Node

15:        906512       43512576  java.util.HashMap

16:         76402       22543104  [Ljava.lang.StackTraceElement;

17:        231233       18500968  [S

......................................................

其中:

[C is a char[]

[S is a short[]

[I is a int[]

[B is a byte[]

[[I is a int[][]

C對象佔用Heap這麼多,每每跟String有關,String其內部使用final char[]數組來保存數據的


五、tomcat jvm 參數

eg.

CATALINA_OPTS="

-server

-Xms6000M

-Xmx6000M

-Xss512k

-XX:NewSize=2250M

-XX:MaxNewSize=2250M

-XX:PermSize=128M

-XX:MaxPermSize=256M

-XX:+AggressiveOpts

-XX:+UseBiasedLocking

-XX:+DisableExplicitGC

-XX:+UseParNewGC

-XX:+UseConcMarkSweepGC

-XX:MaxTenuringThreshold=31

-XX:+CMSParallelRemarkEnabled

-XX:+UseCMSCompactAtFullCollection

-XX:LargePageSizeInBytes=128m

-XX:+UseFastAccessorMethods

-XX:+UseCMSInitiatingOccupancyOnly

-Duser.timezone=Asia/Shanghai

-Djava.awt.headless=true"


eg2.

JAVA_OPTS="-server -Xms22528m -Xmx22528m -Xmn7g -Xss1024K -XX:+UseParallelGC -XX:ParallelGCThreads=30 -XX:TargetSurvivorRatio=85 -verbose:gc -Xloggc:/tmp/civp_gc_$(date +%Y%m%d%H%M%S).log -XX:+PrintGCDateStamps -XX:+PrintGCDe

tails -XX:ErrorFile=/tmp/civp_err_$(date +%Y%m%d%H%M%S).log";


-Xms:表示 Java 初始化堆的大小,-Xms 與-Xmx 設成同樣的值,避免 JVM 反覆從新申請內存,致使性能大起大落,默認值爲物理內存的 1/64,默認(MinHeapFreeRatio參數能夠調整)空餘堆內存小於 40% 時,JVM 就會增大堆直到 -Xmx 的最大限制。


-Xmx:表示最大 Java 堆大小,當應用程序須要的內存超出堆的最大值時虛擬機就會提示內存溢出,而且致使應用服務崩潰,所以通常建議堆的最大值設置爲可用內存的最大值的80%。如何知道個人 JVM 可以使用最大值,使用 java -Xmx512M -version 命令來進行測試,而後逐漸的增大 512 的值,若是執行正常就表示指定的內存大小可用,不然會打印錯誤信息,默認值爲物理內存的 1/4,默認(MinHeapFreeRatio參數能夠調整)空餘堆內存大於 70% 時,JVM 會減小堆直到-Xms 的最小限制。


-Xss:表示每一個 Java 線程堆棧大小,JDK 5.0 之後每一個線程堆棧大小爲 1M,之前每一個線程堆棧大小爲 256K。根據應用的線程所需內存大小進行調整,在相同物理內存下,減少這個值能生成更多的線程,可是操做系統對一個進程內的線程數仍是有限制的,不能無限生成,經驗值在 3000~5000 左右。通常小的應用, 若是棧不是很深, 應該是128k 夠用的,大的應用建議使用 256k 或 512K,通常不易設置超過 1M,要否則容易出現out ofmemory。這個選項對性能影響比較大,須要嚴格的測試。


-XX:NewSize:設置新生代內存大小。

-XX:MaxNewSize:設置最大新生代新生代內存大小

-XX:PermSize:設置持久代內存大小

-XX:MaxPermSize:設置最大值持久代內存大小,永久代不屬於堆內存,堆內存只包含新生代和老年代。

-XX:+AggressiveOpts:做用如其名(aggressive),啓用這個參數,則每當 JDK 版本升級時,你的 JVM 都會使用最新加入的優化技術(若是有的話)。


-XX:+UseBiasedLocking:啓用一個優化了的線程鎖,咱們知道在咱們的appserver,每一個http請求就是一個線程,有的請求短有的請求長,就會有請求排隊的現象,甚至還會出現線程阻塞,這個優化了的線程鎖使得你的appserver內對線程處理自動進行最優調配。

-XX:+DisableExplicitGC:在 程序代碼中不容許有顯示的調用「System.gc()」。每次在到操做結束時手動調用 System.gc() 一下,付出的代價就是系統響應時間嚴重下降,就和關於 Xms,Xmx 裏的解釋的原理同樣,這樣去調用 GC 致使系統的 JVM 大起大落。


-XX:+UseConcMarkSweepGC:設置年老代爲併發收集,即 CMS gc,這一特性只有 jdk1.5

後續版本才具備的功能,它使用的是 gc 估算觸發和 heap 佔用觸發。咱們知道頻頻繁的 GC 會造面 JVM

的大起大落從而影響到系統的效率,所以使用了 CMS GC 後能夠在 GC 次數增多的狀況下,每次 GC 的響應時間卻很短,好比說使用了 CMS

GC 後通過 jprofiler 的觀察,GC 被觸發次數很是多,而每次 GC 耗時僅爲幾毫秒。


-XX:+UseParNewGC:對新生代採用多線程並行回收,這樣收得快,注意最新的 JVM 版本,當使用 -XX:+UseConcMarkSweepGC 時,-XX:UseParNewGC 會自動開啓。所以,若是年輕代的並行 GC 不想開啓,能夠經過設置 -XX:-UseParNewGC 來關掉。


-XX:MaxTenuringThreshold:設置垃圾最大年齡。若是設置爲0的話,則新生代對象不通過 Survivor 區,直接進入老年代。對於老年代比較多的應用(須要大量常駐內存的應用),能夠提升效率。若是將此值設置爲一 個較大值,則新生代對象會在 Survivor 區進行屢次複製,這樣能夠增長對象在新生代的存活時間,增長在新生代即被回收的機率,減小Full GC的頻率,這樣作能夠在某種程度上提升服務穩定性。該參數只有在串行 GC 時纔有效,這個值的設置是根據本地的 jprofiler 監控後獲得的一個理想的值,不能一律而論原搬照抄。


-XX:+CMSParallelRemarkEnabled:在使用 UseParNewGC 的狀況下,儘可能減小 mark 的時間。

-XX:+UseCMSCompactAtFullCollection:在使用 concurrent gc 的狀況下,防止 memoryfragmention,對 live object 進行整理,使 memory 碎片減小。

-XX:LargePageSizeInBytes:指定 Java heap 的分頁頁面大小,內存頁的大小不可設置過大, 會影響 Perm 的大小。

-XX:+UseFastAccessorMethods:使用 get,set 方法轉成本地代碼,原始類型的快速優化。

-XX:+UseCMSInitiatingOccupancyOnly:只有在 oldgeneration 在使用了初始化的比例後 concurrent collector 啓動收集。

-Duser.timezone=Asia/Shanghai:設置用戶所在時區。


-Djava.awt.headless=true:這個參數通常咱們都是放在最後使用的,這全參數的做用是這樣的,有時咱們會在咱們的 J2EE 工程中使用一些圖表工具如:jfreechart,用於在 web 網頁輸出 GIF/JPG 等流,在 winodws 環境下,通常咱們的 app server 在輸出圖形時不會碰到什麼問題,可是在linux/unix 環境下常常會碰到一個 exception 致使你在 winodws 開發環境下圖片顯示的好好但是在 linux/unix 下卻顯示不出來,所以加上這個參數以避免避這樣的狀況出現。

-

Xmn:新生代的內存空間大小,注意:此處的大小是(eden+ 2 survivor space)。與 jmap -heap 中顯示的 New gen 是不一樣的。整個堆大小 = 新生代大小 + 老生代大小 + 永久代大小。在保證堆大小不變的狀況下,增大新生代後,將會減少老生代大小。此值對系統性能影響較大,Sun官方推薦配置爲整個堆的 3/8。


-XX:CMSInitiatingOccupancyFraction:當堆滿以後,並行收集器便開始進行垃圾收集,例如,當沒有足夠的空間來容納新分配或提高的對象。對於 CMS 收集器,長時間等待是不可取的,由於在併發垃圾收集期間應用持續在運行(而且分配對象)。所以,爲了在應用程序使用完內存以前完成垃圾收集週期,CMS 收集器要比並行收集器更先啓動。由於不一樣的應用會有不一樣對象分配模式,JVM 會收集實際的對象分配(和釋放)的運行時數據,而且分析這些數據,來決定何時啓動一次 CMS 垃圾收集週期。這個參數設置有很大技巧,基本上知足(Xmx-Xmn)*(100-CMSInitiatingOccupancyFraction)/100 >= Xmn 就不會出現 promotion failed。例如在應用中 Xmx 是6000,Xmn 是 512,那麼 Xmx-Xmn 是 5488M,也就是老年代有 5488M,CMSInitiatingOccupancyFraction=90 說明老年代到 90% 滿的時候開始執行對老年代的併發垃圾回收(CMS),這時還 剩 10% 的空間是 5488*10% = 548M,因此即便 Xmn(也就是新生代共512M)裏全部對象都搬到老年代裏,548M 的空間也足夠了,因此只要知足上面的公式,就不會出現垃圾回收時的 promotion failed,所以這個參數的設置必須與 Xmn 關聯在一塊兒。


-XX:+CMSIncrementalMode:該標誌將開啓 CMS 收集器的增量模式。增量模式常常暫停 CMS 過程,以便對應用程序線程做出徹底的讓步。所以,收集器將花更長的時間完成整個收集週期。所以,只有經過測試後發現正常 CMS 週期對應用程序線程干擾太大時,才應該使用增量模式。因爲現代服務器有足夠的處理器來適應併發的垃圾收集,因此這種狀況發生得不多,用於但 CPU狀況。

-XX:NewRatio:年輕代(包括 Eden 和兩個 Survivor 區)與年老代的比值(除去持久代),-XX:NewRatio=4 表示年輕代與年老代所佔比值爲 1:4,年輕代佔整個堆棧的 1/5,Xms=Xmx 而且設置了 Xmn 的狀況下,該參數不須要進行設置。

-XX:SurvivorRatio:Eden 區與 Survivor 區的大小比值,設置爲 8,表示 2 個 Survivor 區(JVM 堆內存年輕代中默認有 2 個大小相等的 Survivor 區)與 1 個 Eden 區的比值爲 2:8,即 1 個 Survivor 區佔整個年輕代大小的 1/10。

-XX:+UseSerialGC:設置串行收集器。

-XX:+UseParallelGC:設置爲並行收集器。此配置僅對年輕代有效。即年輕代使用並行收集,而年老代仍使用串行收集。

-XX:+UseParallelOldGC:配置年老代垃圾收集方式爲並行收集,JDK6.0 開始支持對年老代並行收集。


-XX:ConcGCThreads:早期 JVM 版本也叫-XX:ParallelCMSThreads,定義併發 CMS 過程運行時的線程數。好比 value=4 意味着 CMS 週期的全部階段都以 4 個線程來執行。儘管更多的線程會加快併發 CMS 過程,但其也會帶來額外的同步開銷。所以,對於特定的應用程序,應該經過測試來判斷增長 CMS 線程數是否真的可以帶來性能的提高。若是還標誌未設置,JVM 會根據並行收集器中的 -XX:ParallelGCThreads 參數的值來計算出默認的並行 CMS 線程數。

-XX:ParallelGCThreads:配置並行收集器的線程數,即:同時有多少個線程一塊兒進行垃圾回收,此值建議配置與 CPU 數目相等。

-XX:OldSize:設置 JVM 啓動分配的老年代內存大小,相似於新生代內存的初始大小 -XX:NewSize。


以上就是一些經常使用的配置參數,有些參數是能夠被替代的,配置思路須要考慮的是 Java 提供的垃圾回收機制。虛擬機的堆大小決定了虛擬機花費在收集垃圾上的時間和頻度。收集垃圾可以接受的速度和應用有關,應該經過分析實際的垃圾收集的時間和頻率來調整。假如堆的大小很大,那麼徹底垃圾收集就會很慢,可是頻度會下降。假如您把堆的大小和內存的須要一致,徹底收集就很快,可是會更加頻繁。調整堆大小的的目的是最小化垃圾收集的時間,以在特定的時間內最大化處理客戶的請求。在基準測試的時候,爲確保最好的性能,要把堆的大小設大,確保垃圾收集不在整個基準測試的過程當中出現。

假如系統花費不少的時間收集垃圾,請減少堆大小。一次徹底的垃圾收集應該不超過 3-5 秒。假如垃圾收集成爲瓶頸,那麼須要指定代的大小,檢查垃圾收集的周詳輸出,研究垃圾收集參數對性能的影響。當增長處理器時,記得增長內存,由於分配可以並行進行,而垃圾收集不是並行的。

相關文章
相關標籤/搜索