天天看點

Java GC(垃圾回收)

1.java中GC

    即垃圾收集機制是指jvm用于釋放那些不再使用的對象所占用的記憶體。java語言并不要求jvm有gc,也沒有規定gc如何工作。不過常用的jvm都有gc,而且大多數gc都使用類似的算法管理記憶體和執行收集操作。

    垃圾收集的目的在于清除不再使用的對象。gc通過确定對象是否被活動對象引用來确定是否收集該對象。gc首先要判斷該對象是否是時候可以收集。兩種常用的方法是引用計數和對象引用周遊。

1.1.引用計數

引用計數存儲對特定對象的所有引用數,也就是說,當應用程式建立引用以及引用超出範圍時,jvm必須适當增減引用數。當某對象的引用數為0時,便可以進行垃圾收集。

1.2.對象引用周遊

早期的jvm使用引用計數,現在大多數jvm采用對象引用周遊。對象引用周遊從一組對象開始,沿着整個對象圖上的每條連結,遞歸确定可到達(reachable)的對象。如果某對象不能從這些根對象的一個(至少一個)到達,則将它作為垃圾收集。在對象周遊階段,gc必須記住哪些對象可以到達,以便删除不可到達的對象,這稱為标記(marking)對象。

然後,gc要删除不可到達的對象。删除時,有些gc隻是簡單的掃描堆棧,删除未标記的對象,并釋放它們的記憶體以生成新的對象,這叫做清除(sweeping)。這種方法的問題在于記憶體會分成好多小段,而它們不足以用于新的對象,但是組合起來卻很大。是以,許多gc可以重新組織記憶體中的對象,并進行壓縮(compact),形成可利用的空間。

為此,gc需要停止其他的活動活動。這種方法意味着所有與應用程式相關的工作停止,隻有gc運作。結果,在響應期間增減了許多混雜請求。另外,更複雜的 gc不斷增加或同時運作以減少或者清除應用程式的中斷。有的gc使用單線程完成這項工作,有的則采用多線程以增加效率。

幾種垃圾回收機制

2.1.标記-清除收集器

這種收集器首先周遊對象圖并标記可到達的對象,然後掃描堆棧以尋找未标記對象并釋放它們的記憶體。這種收集器一般使用單線程工作并停止其他操作。

2.2.标記-壓縮收集器

有時也叫标記-清除-壓縮收集器,與标記-清除收集器有相同的标記階段。在第二階段,則把标記對象複制到堆棧的新域中以便壓縮堆棧。這種收集器也停止其他操作。

2.3.複制收集器

這種收集器将堆棧分為兩個域,常稱為半空間。每次僅使用一半的空間,jvm生成的新對象則放在另一半空間中。gc運作時,它把可到達對象複制到另一半空間,進而壓縮了堆棧。這種方法适用于短生存期的對象,持續複制長生存期的對象則導緻效率降低。

2.4.增量收集器

增量收集器把堆棧分為多個域,每次僅從一個域收集垃圾。這會造成較小的應用程式中斷。

2.5.分代收集器

這種收集器把堆棧分為兩個或多個域,用以存放不同壽命的對象。jvm生成的新對象一般放在其中的某個域中。過一段時間,繼續存在的對象将獲得使用期并轉入更長壽命的域中。分代收集器對不同的域使用不同的算法以優化性能。

2.6.并發收集器

并發收集器與應用程式同時運作。這些收集器在某點上(比如壓縮時)一般都不得不停止其他操作以完成特定的任務,但是因為其他應用程式可進行其他的背景操作,是以中斷其他處理的實際時間大大降低。

2.7.并行收集器

并行收集器使用某種傳統的算法并使用多線程并行的執行它們的工作。在多cpu機器上使用多線程技術可以顯著的提高java應用程式的可擴充性。

3.Sun HotSpot

3.1 JVM堆大小的調整

Sun HotSpot 1.4.1使用分代收集器,它把堆分為三個主要的域:新域、舊域以及永久域。Jvm生成的所有新對象放在新域中。一旦對象經曆了一定數量的垃圾收集循環後,便獲得使用期并進入舊域。在永久域中jvm則存儲class和method對象。就配置而言,永久域是一個獨立域并且不認為是堆的一部分。

下面介紹如何控制這些域的大小。可使用-Xms和-Xmx 控制整個堆的原始大小或最大值。

下面的指令是把初始大小設定為128M:

java –Xms128m

–Xmx256m為控制新域的大小,可使用-XX:NewRatio設定新域在堆中所占的比例。

下面的指令把整個堆設定成128m,新域比率設定成3,即新域與舊域比例為1:3,新域為堆的1/4或32M:

java –Xms128m –Xmx128m

–XX:NewRatio =3可使用-XX:NewSize和-XX:MaxNewsize設定新域的初始值和最大值。

下面的指令把新域的初始值和最大值設定成64m:

java –Xms256m –Xmx256m –Xmn64m

永久域預設大小為4m。運作程式時,jvm會調整永久域的大小以滿足需要。每次調整時,jvm會對堆進行一次完全的垃圾收集。

使用-XX:MaxPerSize标志來增加永久域搭大小。在WebLogic Server應用程式加載較多類時,經常需要增加永久域的最大值。當jvm加載類時,永久域中的對象急劇增加,進而使jvm不斷調整永久域大小。為了避免調整,可使用-XX:PerSize标志設定初始值。

下面把永久域初始值設定成32m,最大值設定成64m。

java -Xms512m -Xmx512m -Xmn128m -XX:PermSize=32m -XX:MaxPermSize=64m

預設狀态下,HotSpot在新域中使用複制收集器。該域一般分為三個部分。第一部分為Eden,用于生成新的對象。另兩部分稱為救助空間,當Eden 充滿時,收集器停止應用程式,把所有可到達對象複制到目前的from救助空間,一旦目前的from救助空間充滿,收集器則把可到達對象複制到目前的to救助空間。From和to救助空間互換角色。維持活動的對象将在救助空間不斷複制,直到它們獲得使用期并轉入舊域。使用-XX:SurvivorRatio 可控制新域子空間的大小。

同NewRation一樣,SurvivorRation規定某救助域與Eden空間的比值。比如,以下指令把新域設定成64m,Eden占32m,每個救助域各占16m:

java -Xms256m -Xmx256m -Xmn64m -XX:SurvivorRation =2

如前所述,預設狀态下HotSpot對新域使用複制收集器,對舊域使用标記-清除-壓縮收集器。在新域中使用複制收集器有很多意義,因為應用程式生成的大部分對象是短壽命的。理想狀态下,所有過渡對象在移出Eden空間時将被收集。如果能夠這樣的話,并且移出Eden空間的對象是長壽命的,那麼理論上可以立即把它們移進舊域,避免在救助空間反複複制。但是,應用程式不能适合這種理想狀态,因為它們有一小部分中長壽命的對象。最好是保持這些中長壽命的對象并放在新域中,因為複制小部分的對象總比壓縮舊域廉價。為控制新域中對象的複制,可用-XX:TargetSurvivorRatio控制救助空間的比例(該值是設定救助空間的使用比例。如救助空間位1M,該值50表示可用500K)。該值是一個百分比,預設值是50。當較大的堆棧使用較低的 sruvivorratio時,應增加該值到80至90,以更好利用救助空間。用-XX:maxtenuring threshold可控制上限。

為放置所有的複制全部發生以及希望對象從eden擴充到舊域,可以把MaxTenuring Threshold設定成0。設定完成後,實際上就不再使用救助空間了,是以應把SurvivorRatio設成最大值以最大化Eden空間,設定如下:

java … -XX:MaxTenuringThreshold=0 –XX:SurvivorRatio=50000 …

4.BEA JRockit JVM的使用

Bea WebLogic 8.1使用的新的JVM用于Intel平台。在Bea安裝完畢的目錄下可以看到有一個類似于jrockit81sp1_141_03的檔案夾。這就是 Bea新JVM所在目錄。不同于HotSpot把Java位元組碼編譯成本地碼,它預先編譯成類。JRockit還提供了更細緻的功能用以觀察JVM的運作狀态,主要是獨立的GUI控制台(隻能适用于使用Jrockit才能使用jrockit81sp1_141_03自帶的console監控一些cpu及 memory參數)或者WebLogic Server控制台。

Bea JRockit JVM支援4種垃圾收集器:

4.1.1.分代複制收集器

它與預設的分代收集器工作政策類似。對象在新域中配置設定,即JRockit文檔中的nursery。這種收集器最适合單cpu機上小型堆操作。

4.1.2.單空間并發收集器

該收集器使用完整堆,并與背景線程共同工作。盡管這種收集器可以消除中斷,但是收集器需花費較長的時間尋找死對象,而且處理應用程式時收集器經常運作。如果處理器不能應付應用程式産生的垃圾,它會中斷應用程式并關閉收集。

分代并發收集器這種收集器在護理域使用排它複制收集器,在舊域中則使用并發收集器。由于它比單空間共同發生收集器中斷頻繁,是以它需要較少的記憶體,應用程式的運作效率也較高,注意,過小的護理域可以導緻大量的臨時對象被擴充到舊域中。這會造成收集器超負荷運作,甚至采用排它性工作方式完成收集。

4.1.3.并行收集器

該收集器也停止其他程序的工作,但使用多線程以加速收集程序。盡管它比其他的收集器易于引起長時間的中斷,但一般能更好的利用記憶體,程式效率也較高。

預設狀态下,JRockit使用分代并發收集器。要改變收集器,可使用-Xgc:,對應四個收集器分别為 gencopy,singlecon,gencon以及parallel。可使用-Xms和-Xmx設定堆的初始大小和最大值。要設定護理域,則使用- Xns:java –jrockit –Xms512m –Xmx512m –Xgc:gencon –Xns128m…盡管JRockit支援-verbose:gc開關,但它輸出的資訊會因收集器的不同而異。JRockit還支援memory、 load和codegen的輸出。

注意 :如果 使用JRockit JVM的話還可以使用WLS自帶的console(C:\bea\jrockit81sp1_141_03\bin下)來監控一些資料,如cpu, memery等。要想能構監控必須在啟動服務時startWeblogic.cmd中加入-Xmanagement參數。

5.如何從JVM中擷取資訊來進行調整

-verbose.gc開關可顯示gc的操作内容。打開它,可以顯示最忙和最空閑收集行為發生的時間、收集前後的記憶體大小、收集需要的時間等。打開- xx:+ printgcdetails開關,可以詳細了解gc中的變化。打開-XX: + PrintGCTimeStamps開關,可以了解這些垃圾收集發生的時間,自jvm啟動以後以秒計量。最後,通過-xx: + PrintHeapAtGC開關了解堆的更詳細的資訊。為了了解新域的情況,可以通過-XX:=PrintTenuringDistribution開關了解獲得使用期的對象權。

6.Pdm系統JVM調整

6.1.伺服器:前提記憶體1G 單CPU

可通過如下參數進行調整:-server 啟用伺服器模式(如果CPU多,伺服器機建議使用此項)

-Xms,-Xmx一般設為同樣大小。 800m

-Xmn 是将NewSize與MaxNewSize設為一緻。320m

-XX:PerSize 64m

-XX:NewSize 320m 此值設大可調大新對象區,減少Full GC次數

-XX:MaxNewSize 320m

-XX:NewRato NewSize設了可不設。

-XX: SurvivorRatio

-XX:userParNewGC 可用來設定并行收集

-XX:ParallelGCThreads 可用來增加并行度

-XXUseParallelGC 設定後可以使用并行清除收集器

-XX:UseAdaptiveSizePolicy 與上面一個聯合使用效果更好,利用它可以自動優化新域大小以及救助空間比值

6.2.客戶機:通過在JNLP檔案中設定參數來調整用戶端JVM

JNLP中參數:initial-heap-size和max-heap-size

這可以在framework的RequestManager中生成JNLP檔案時加入上述參數,但是這些值是要求根據客戶機的硬體狀态變化的(如客戶機的記憶體大小等)。建議這兩個參數值設為客戶機可用記憶體的60%(有待測試)。為了在動态生成JNLP時以上兩個參數值能夠随客戶機不同而不同,可靠慮獲得客戶機系統資訊并将這些嵌到首頁index.jsp中作為連接配接請求的參數。

在設定了上述參數後可以通過Visualgc 來觀察垃圾回收的一些參數狀态,再做相應的調整來改善性能。一般的标準是減少fullgc的次數,最好硬體支援使用并行垃圾回收(要求多CPU)。

7.JVM GC參數設定

1: heap size

a: -Xmx

指定jvm的最大heap大小,如:-Xmx2g

b: -Xms

指定jvm的最小heap大小,如:-Xms1g

c: -Xmn

指定jvm中New Generation的大小,如:-Xmn256m

d: -XX:PermSize

指定jvm中Perm Generation的最小值,如:-XX:PermSize=32m

e: -XX:MaxPermSize

指定Perm Generation的最大值,如:-XX:MaxPermSize=64m

f: -Xss

指定線程桟大小,如:-Xss128k

g: -XX:NewRatio

指定jvm中Old Generation heap size與New Generation的比例,在使用CMS GC的情況下此參數失效, 如:-XX:NewRatio=2

h: -XX:SurvivorRatio

指定New Generation中Eden Space與一個Survivor Space的heap size比例,-XX:SurvivorRatio=8,那麼在總共New Generation為10m的情況下,Eden Space為8m

i: -XX:MinHeapFreeRatio

指定jvm heap在使用率小于n的情況下,heap進行收縮,Xmx==Xms的情況下無效,如:-XX:MinHeapFreeRatio=30

j: -XX:MaxHeapFreeRatio

指定jvm heap在使用率大于n的情況下,heap進行擴張,Xmx==Xms的情況下無效,如:-XX:MaxHeapFreeRatio=70

k: -XX:LargePageSizeInBytes

指定Java heap的分頁頁面大小,如:-XX:LargePageSizeInBytes=128m

2: garbage collector

a: -XX:+UseParallelGC

指定在New Generation使用parallel collector,并行收集,同時啟動多個垃圾回收thread,不能和CMS gc一起使用.系統噸吐量優先,但是會有較長長時間的app pause,背景系統任務可以使用此gc

b: -XX:ParallelGCThreads

指定parallel collection時啟動的thread個數,預設是實體processor的個數,如:-xx:ParallelGCThreads=8

c: -XX:+UseParallelOldGC

指定在Old Generation使用parallel collector

d: -XX:+UseParNewGC

指定在New Generation使用parallel collector,是UseParallelGC的gc的更新版本,有更好的性能或者優點,可以和CMS gc一起使用

e: -XX:+CMSParallelRemarkEnabled

在使用UseParNewGC的情況下,盡量減少mark的時間

f: -XX:+UseConcMarkSweepGC

指定在Old Generation使用concurrent cmark sweep gc,gc thread和app thread并行,是以稱作concurrent.app pause時間較短,适合互動性強的系統,如web server

g: -XX:+UseCMSCompactAtFullCollection

在使用concurrent gc的情況下,防止memory fragmention,對live object進行整理,使memory碎片減少

h: -XX:CMSInitiatingOccupancyFraction=n

訓示在old generation在使用了n%的比例後,啟動concurrent collector,預設值是68,如:-XX:CMSInitiatingOccupancyFraction=70

有個bug,在低版本的jvm上出現,http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6486089

i: -XX:+UseCMSInitiatingOccupancyOnly

訓示隻有在old generation在使用了初始化的比例後concurrent collector啟動收集

3:others

a: -XX:MaxTenuringThreshold

指定一個object在經曆了n次young gc後轉移到old generation區,在linux64的java6下預設值是15,此參數對于throughput collector無效,如:-XX:MaxTenuringThreshold=31

b: -XX:+DisableExplicitGC

禁止java程式中的full gc,如System.gc()的調用

c: -XX:+UseFastAccessorMethods

原始類型get,set方法的優化

d: -XX:+PrintGCDetails

打應垃圾收集的情況如:

[GC 15610.466: [ParNew: 229689K->20221K(235968K), 0.0194460 secs] 1159829K->953935K(2070976K), 0.0196420 secs]

e: -XX:+PrintGCTimeStamps

打應垃圾收集的時間情況,如:

[Times: user=0.09 sys=0.00, real=0.02 secs]

f: -XX:+PrintGCApplicationStoppedTime

打應垃圾收集時,系統的停頓時間,如:

Total time for which application threads were stopped: 0.0225920 seconds

4 -XX:+UseCompressedOops

    壓縮指針 64位機器,JDK1.6支援 Java 6 JVM參數選項大全  

 8.jstat

1. jstat -gc pid

            可以顯示gc的資訊,檢視gc的次數,及時間。

            其中最後五項,分别是young gc的次數,young gc的時間,full gc的次數,full gc的時間,gc的總時間。

2.jstat -gccapacity pid

            可以顯示,VM記憶體中三代(young,old,perm)對象的使用和占用大小,

            如:PGCMN顯示的是最小perm的記憶體使用量,PGCMX顯示的是perm的記憶體最大使用量,

            PGC是目前新生成的perm記憶體占用量,PC是但前perm記憶體占用量。

            其他的可以根據這個類推, OC是old内純的占用量。

3.jstat -gcutil pid

            統計gc資訊統計。

4.jstat -gcnew pid

           年輕代對象的資訊。

5.jstat -gcnewcapacity pid

           年輕代對象的資訊及其占用量。

6.jstat -gcold pid

          old代對象的資訊。

7.stat -gcoldcapacity pid

          old代對象的資訊及其占用量。

8.jstat -gcpermcapacity pid

          perm對象的資訊及其占用量。

9.jstat -class pid

          顯示加載class的數量,及所占空間等資訊。

10.jstat -compiler pid

          顯示VM實時編譯的數量等資訊。

11.stat -printcompilation pid

          目前VM執行的資訊。

        一些術語的中文解釋:

         S0C:年輕代中第一個survivor(幸存區)的容量 (位元組)

         S1C:年輕代中第二個survivor(幸存區)的容量 (位元組)

         S0U:年輕代中第一個survivor(幸存區)目前已使用空間 (位元組)

         S1U:年輕代中第二個survivor(幸存區)目前已使用空間 (位元組)

           EC:年輕代中Eden(伊甸園)的容量 (位元組)

           EU:年輕代中Eden(伊甸園)目前已使用空間 (位元組)

           OC:Old代的容量 (位元組)

           OU:Old代目前已使用空間 (位元組)

           PC:Perm(持久代)的容量 (位元組)

           PU:Perm(持久代)目前已使用空間 (位元組)

         YGC:從應用程式啟動到采樣時年輕代中gc次數

       YGCT:從應用程式啟動到采樣時年輕代中gc所用時間(s)

         FGC:從應用程式啟動到采樣時old代(全gc)gc次數

       FGCT:從應用程式啟動到采樣時old代(全gc)gc所用時間(s)

         GCT:從應用程式啟動到采樣時gc用的總時間(s)

    NGCMN:年輕代(young)中初始化(最小)的大小 (位元組)

    NGCMX:年輕代(young)的最大容量 (位元組)

        NGC:年輕代(young)中目前的容量 (位元組)

   OGCMN:old代中初始化(最小)的大小 (位元組)

   OGCMX:old代的最大容量 (位元組)

       OGC:old代目前新生成的容量 (位元組)

   PGCMN:perm代中初始化(最小)的大小 (位元組)

   PGCMX:perm代的最大容量 (位元組) 

       PGC:perm代目前新生成的容量 (位元組)

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

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

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

           O:old代已使用的占目前容量百分比

           P:perm代已使用的占目前容量百分比

  S0CMX:年輕代中第一個survivor(幸存區)的最大容量 (位元組)

S1CMX :年輕代中第二個survivor(幸存區)的最大容量 (位元組)

    ECMX:年輕代中Eden(伊甸園)的最大容量 (位元組)

       DSS:目前需要survivor(幸存區)的容量 (位元組)(Eden區已滿)

          TT: 持有次數限制

       MTT : 最大持有次數限制

更多深入,請參考測試天堂

JVM性能參數調優實踐,不會執行Full GC,網站無停滞

JVM參數調優是個很頭痛的問題,設定的不好,JVM不斷執行Full GC,導緻整個系統變得很慢,網站停滞時間能達10秒以上,這種情況如果沒隔幾分鐘就來一次,自己都受不了。這種停滞在測試的時候看不出來,隻有網站pv達到數十萬/天的時候問題就暴露出來了。

要想配置好JVM參數,需要對年輕代、年老代、救助空間和永久代有一定了解,還要了解jvm記憶體管理邏輯,最終還要根據自己的應用來做調整。關于JVM參數上網一搜就能搜出一大把,也有很多提供實踐的例子,我也按照各種例子測試過,最終還是會出現問題。

經過幾個月的實踐改善,我就網站(要求無停滞時間)的jvm參數調優給出以下幾條經驗。

1:建議用64位作業系統,Linux下64位的jdk比32位jdk要慢一些,但是吃得記憶體更多,吞吐量更大。

2:XMX和XMS設定一樣大,MaxPermSize和MinPermSize設定一樣大,這樣可以減輕伸縮堆大小帶來的壓力。

3:調試的時候設定一些列印參數,如-XX:+PrintClassHistogram -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -Xloggc:log/gc.log,這樣可以從gc.log裡看出一些端倪出來。

4:系統停頓的時候可能是GC的問題也可能是程式的問題,多用jmap和jstack檢視,或者killall -3 java,然後檢視java控制台日志,能看出很多問題。有一次,網站突然很慢,jstack一看,原來是自己寫的URLConnection連接配接太多沒有釋放,改一下程式就OK了。

5:仔細了解自己的應用,如果用了緩存,那麼年老代應該大一些,緩存的HashMap不應該無限制長,建議采用LRU算法的Map做緩存,LRUMap的最大長度也要根據實際情況設定。

6:垃圾回收時promotion failed是個很頭痛的問題,一般可能是兩種原因産生,第一個原因是救助空間不夠,救助空間裡的對象還不應該被移動到年老代,但年輕代又有很多對象需要放入救助空間;第二個原因是年老代沒有足夠的空間接納來自年輕代的對象;這兩種情況都會轉向Full GC,網站停頓時間較長。第一個原因我的最終解決辦法是去掉救助空間,設定-XX:SurvivorRatio=65536 -XX:MaxTenuringThreshold=0即可,第二個原因我的解決辦法是設定CMSInitiatingOccupancyFraction為某個值(假設70),這樣年老代空間到70%時就開始執行CMS,年老代有足夠的空間接納來自年輕代的對象。

7:不管怎樣,永久代還是會逐漸變滿,是以隔三差五重起java伺服器是必要的,我每天都自動重起。

8:采用并發回收時,年輕代小一點,年老代要大,因為年老大用的是并發回收,即使時間長點也不會影響其他程式繼續運作,網站不會停頓。

我的最終配置如下(系統8G記憶體),每天幾百萬pv一點問題都沒有,網站沒有停頓,2009年shedewang.com沒有因為記憶體問題down過機。

$JAVA_ARGS .= " -Dresin.home=$SERVER_ROOT -server -Xms6000M -Xmx6000M -Xmn500M -XX:PermSize=500M -XX:MaxPermSize=500M -XX:SurvivorRatio=65536 -XX:MaxTenuringThreshold=0 -Xnoclassgc -XX:+DisableExplicitGC -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:+CMSClassUnloadingEnabled -XX:-CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=90 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+PrintClassHistogram -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -Xloggc:log/gc.log ";

說明一下, -XX:SurvivorRatio=65536 -XX:MaxTenuringThreshold=0就是去掉了救助空間;

-Xnoclassgc禁用類垃圾回收,性能會高一點;

-XX:+DisableExplicitGC禁止System.gc(),免得程式員誤調用gc方法影響性能;

-XX:+UseParNewGC,對年輕代采用多線程并行回收,這樣收得快;

帶CMS參數的都是和并發回收相關的,不明白的可以上網搜尋;

CMSInitiatingOccupancyFraction,這個參數設定有很大技巧,基本上滿足(Xmx-Xmn)*(100-CMSInitiatingOccupancyFraction)/100>=Xmn就不會出現promotion failed。在我的應用中Xmx是6000,Xmn是500,那麼Xmx-Xmn是5500兆,也就是年老代有5500兆,CMSInitiatingOccupancyFraction=90說明年老代到90%滿的時候開始執行對年老代的并發垃圾回收(CMS),這時還剩10%的空間是5500*10%=550兆,是以即使Xmn(也就是年輕代共500兆)裡所有對象都搬到年老代裡,550兆的空間也足夠了,是以隻要滿足上面的公式,就不會出現垃圾回收時的promotion failed;

SoftRefLRUPolicyMSPerMB這個參數我認為可能有點用,官方解釋是softly reachable objects will remain alive for some amount of time after the last time they were referenced. The default value is one second of lifetime per free megabyte in the heap,我覺得沒必要等1秒;

網上其他介紹JVM參數的也比較多,估計其中大部分是沒有遇到promotion failed,或者通路量太小沒有機會遇到,(Xmx-Xmn)*(100-CMSInitiatingOccupancyFraction)/100>=Xmn這個公式絕對是原創,真遇到promotion failed了,還得這麼處理。