本文由CrowHawk翻譯,位址:如何優化Java GC「譯」,是Java GC調優的經典佳作。
Sangmin Lee發表在Cubrid上的"Become a Java GC Expert"系列文章的第三篇《How to Tune Java Garbage Collection》,本文的作者是南韓人,寫在JDK 1.8釋出之前,雖然有些地方有些許過時,但整體内容還是非常有價值的。譯者此前也看到有人翻譯了本文,發現其中有許多錯漏生硬和語焉不詳之處,是以決定自己翻譯一份,供大家分享。
本文是“成為Java GC專家”系列文章的第三篇,在系列的第一篇文章《了解Java GC》中,我們了解到了不同GC算法的執行過程、GC的工作原理、新生代和老年代的概念、JDK 7中你需要了解的5種GC類型以及每一種GC對性能的影響。
在系列的第二篇文章《如何監控Java GC》中筆者已經解釋了JVM進行實時GC的原理、監控GC的方法以及可以使這一過程更加迅速高效的工具。
在第三篇文章中,筆者将基于實際生産環境中的案例,介紹幾個GC優化的最佳參數設定。在此我們假設你已經了解了本系列前兩篇文章的内容,是以為了更深入的了解本文所講内容,我建議你在閱讀本篇文章之前先仔細閱讀這兩篇文章。
## GC優化是必要的嗎?
或者更準确地說,GC優化對Java基礎服務來說是必要的嗎?答案是否定的,事實上GC優化對Java基礎服務來說在有些場合是可以省去的,但前提是這些正在運作的Java系統,必須包含以下參數或行為:
- 記憶體大小已經通過-Xms和-Xmx參數指定過
- 運作在server模式下(使用-server參數)
- 系統中沒有殘留逾時日志之類的錯誤日志
換句話說,如果你在運作時沒有手動設定記憶體大小并且列印出了過多的逾時日志,那你就需要對系統進行GC優化。
不過你需要時刻謹記一句話:GC tuning is the last task to be done.
現在來想一想GC優化的最根本原因,垃圾收集器的工作就是清除Java建立的對象,垃圾收集器需要清理的對象數量以及要執行的GC數量均取決于已建立的對象數量。是以,為了使你的系統在GC上表現良好,首先需要減少建立對象的數量。
俗話說“冰凍三尺非一日之寒”,我們在編碼時要首先要把下面這些小細節做好,否則一些瑣碎的不良代碼累積起來将讓GC的工作變得繁重而難于管理:
- 使用
或StringBuilder
來代替StringBuffer
String
- 盡量少輸出日志
盡管如此,仍然會有我們束手無策的情況。XML和JSON解析過程往往占用了最多的記憶體,即使我們已經盡可能地少用String、少輸出日志,仍然會有大量的臨時記憶體(大約10-100MB)被用來解析XML或JSON檔案,但我們又很難棄用XML和JSON。在此,你隻需要知道這一過程會占據大量記憶體即可。
如果在經過幾次重複的優化後應用程式的記憶體用量情況有所改善,那麼久可以啟動GC優化了。
筆者總結了GC優化的兩個目的:
- 将進入老年代的對象數量降到最低
- 減少Full GC的執行時間
## 将進入老年代的對象數量降到最低
除了可以在JDK 7及更高版本中使用的G1收集器以外,其他分代GC都是由Oracle JVM提供的。關于分代GC,就是對象在Eden區被建立,随後被轉移到Survivor區,在此之後剩餘的對象會被轉入老年代。也有一些對象由于占用記憶體過大,在Eden區被建立後會直接被傳入老年代。老年代GC相對來說會比新生代GC更耗時,是以,減少進入老年代的對象數量可以顯著降低Full GC的頻率。你可能會以為減少進入老年代的對象數量意味着把它們留在新生代,事實正好相反,新生代記憶體的大小是可以調節的。
## 降低Full GC的時間
Full GC的執行時間比Minor GC要長很多,是以,如果在Full GC上花費過多的時間(超過1s),将可能出現逾時錯誤。
- 如果通過減小老年代記憶體來減少Full GC時間,可能會引起
或者導緻Full GC的頻率升高。OutOfMemoryError
- 另外,如果通過增加老年代記憶體來降低Full GC的頻率,Full GC的時間可能是以增加。
是以,你需要把老年代的大小設定成一個“合适”的值。
## 影響GC性能的參數
正如我在系列的第一篇文章《了解Java GC》末尾提到的,不要幻想着“如果有人用他設定的GC參數擷取了不錯的性能,我們為什麼不複制他的參數設定呢?”,因為對于不用的Web服務,它們建立的對象大小和生命周期都不相同。
舉一個簡單的例子,如果一個任務的執行條件是A,B,C,D和E,另一個完全相同的任務執行條件隻有A和B,那麼哪一個任務執行速度更快呢?作為常識來講,答案很明顯是後者。
Java GC參數的設定也是這個道理,設定好幾個參數并不會提升GC執行的速度,反而會使它變得更慢。GC優化的基本原則是将不同的GC參數應用到兩個及以上的伺服器上然後比較它們的性能,然後将那些被證明可以提高性能或減少GC執行時間的參數應用于最終的工作伺服器上。
下面這張表展示了與記憶體大小相關且會影響GC性能的GC參數
表1:GC優化需要考慮的JVM參數
類型 | 參數 | 描述 |
---|---|---|
堆記憶體大小 | | 啟動JVM時堆記憶體的大小 |
| 堆記憶體最大限制 | |
新生代空間大小 | | 新生代和老年代的記憶體比 |
| 新生代記憶體大小 | |
| Eden區和Survivor區的記憶體比 |
筆者在進行GC優化時最常用的參數是
-Xms
,
-Xmx
和
-XX:NewRatio
。
-Xms
-Xmx
參數通常是必須的,是以
NewRatio
的值将對GC性能産生重要的影響。
有些人可能會問如何設定永久代記憶體大小,你可以用
-XX:PermSize
-XX:MaxPermSize
參數來進行設定,但是要記住,隻有當出現
OutOfMemoryError
錯誤時你才需要去設定永久代記憶體。
還有一個會影響GC性能的因素是垃圾收集器的類型,下表展示了關于GC類型的可選參數(基于JDK 6.0):
表2:GC類型可選參數
GC類型 | 備注 | |
---|---|---|
Serial GC | -XX:+UseSerialGC | |
Parallel GC | -XX:+UseParallelGC -XX:ParallelGCThreads=value | |
Parallel Compacting GC | -XX:+UseParallelOldGC | |
CMS GC | -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=value -XX:+UseCMSInitiatingOccupancyOnly | |
G1 | -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC | 在JDK 6中這兩個參數必須配合使用 |
除了G1收集器外,可以通過設定上表中每種類型第一行的參數來切換GC類型,最常見的非侵入式GC就是Serial GC,它針對用戶端系統進行了特别的優化。
會影響GC性能的參數還有很多,但是上述的參數會帶來最顯著的效果,請切記,設定太多的參數并不一定會提升GC的性能。
## GC優化的過程
GC優化的過程和大多數常見的提升性能的過程相似,下面是筆者使用的流程:
1.監控GC狀态
你需要監控GC進而檢查系統中運作的GC的各種狀态,具體方法請檢視系列的第二篇文章《如何監控Java GC》
2.分析監控結果後決定是否需要優化GC
在檢查GC狀态後,你需要分析監控結構并決定是否需要進行GC優化。如果分析結果顯示運作GC的時間隻有0.1-0.3秒,那麼就不需要把時間浪費在GC優化上,但如果運作GC的時間達到1-3秒,甚至大于10秒,那麼GC優化将是很有必要的。
但是,如果你已經配置設定了大約10GB記憶體給Java,并且這些記憶體無法省下,那麼就無法進行GC優化了。在進行GC優化之前,你需要考慮為什麼你需要配置設定這麼大的記憶體空間,如果你配置設定了1GB或2GB大小的記憶體并且出現了
OutOfMemoryError
,那你就應該執行堆轉儲(heap dump)來消除導緻異常的原因。
注意:
堆轉儲(heap dump)是一個用來檢查Java記憶體中的對象和資料的記憶體檔案。該檔案可以通過執行JDK中的 jmap
指令來建立。在建立檔案的過程中,所有Java程式都将暫停,是以,不要再系統執行過程中建立該檔案。
你可以在網際網路上搜尋heap dump的詳細說明。對于南韓讀者,可以直接參考我去年釋出的書:《The story of troubleshooting for Java developers and system operators》 (Sangmin Lee, Hanbit Media, 2011, 416 pages)
3.設定GC類型/記憶體大小
如果你決定要進行GC優化,那麼你需要選擇一個GC類型并且為它設定記憶體大小。此時如果你有多個伺服器,請如上文提到的那樣,在每台機器上設定不同的GC參數并分析它們的差別。
4.分析結果
在設定完GC參數後就可以開始收集資料,請在收集至少24小時後再進行結果分析。如果你足夠幸運,你可能會找到系統的最佳GC參數。如若不然,你還需要分析輸出日志并檢查配置設定的記憶體,然後需要通過不斷調整GC類型/記憶體大小來找到系統的最佳參數。
5.如果結果令人滿意,将參數應用到所有伺服器上并結束GC優化
如果GC優化的結果令人滿意,就可以将參數應用到所有伺服器上,并停止GC優化。
在下面的章節中,你将會看到上述每一步所做的具體工作。
## 監控GC狀态并分析結果
在運作中的Web應用伺服器(Web Application Server,WAS)上檢視GC狀态的最佳方式就是使用
jstat
指令。筆者在《如何監控Java GC》中已經介紹過了
jstat
指令,是以在本篇文章中我将着重關注資料部分。
下面的例子展示了某個還沒有執行GC優化的JVM的狀态(雖然它并不是運作伺服器)。
$ jstat -gcutil 21719 1s
S0 S1 E O P YGC YGCT FGC FGCT GCT
48.66 0.00 48.10 49.70 77.45 3428 172.623 3 59.050 231.673
48.66 0.00 48.10 49.70 77.45 3428 172.623 3 59.050 231.673
我們先看一下YGC(從應用程式啟動到采樣時發生 Young GC 的次數)和YGCT(從應用程式啟動到采樣時 Young GC 所用的時間(秒)),計算YGCT/YGC會得出,平均每次新生代的GC耗時50ms,這是一個很小的數字,通過這個結果可以看出,我們大可不必關注新生代GC對GC性能的影響。
現在來看一下FGC( 從應用程式啟動到采樣時發生 Full GC 的次數)和FGCT(從應用程式啟動到采樣時 Full GC 所用的時間(秒)),計算FGCT/FGC會得出,平均每次老年代的GC耗時19.68s。有可能是執行了三次Full GC,每次耗時19.68s,也有可能是有兩次隻花了1s,另一次花了58s。不管是哪一種情況,GC優化都是很有必要的。
jstat
指令可以很容易地檢視GC狀态,但是分析GC的最佳方式是加上
-verbosegc
參數來生成日志。在之前的文章中筆者已經解釋了如何分析這些日志。HPJMeter是筆者最喜歡的用于分析
-verbosegc
生成的日志的工具,它簡單易用,使用HPJmeter可以很容易地檢視GC執行時間以及GC發生頻率。
此外,如果GC執行時間滿足下列所有條件,就沒有必要進行GC優化了:
- Minor GC執行非常迅速(50ms以内)
- Minor GC沒有頻繁執行(大約10s執行一次)
- Full GC執行非常迅速(1s以内)
- Full GC沒有頻繁執行(大約10min執行一次)
括号中的數字并不是絕對的,它們也随着服務的狀态而變化。有些服務可能要求一次Full GC在0.9s以内,而有些則會放得更寬一些。是以,對于不同的服務,需要按照不同的标準考慮是否需要執行GC優化。
當檢查GC狀态時,不能隻檢視Minor GC和Full GC的時間,還必須要關注GC執行的次數。如果新生代空間太小,Minor GC将會非常頻繁地執行(有時每秒會執行一次,甚至更多)。此外,傳入老年代的對象數目會上升,進而導緻Full GC的頻率升高。是以,在執行
jstat
指令時,請使用
-gccapacity
參數來檢視具體占用了多少空間。
## 設定GC類型/記憶體大小
設定GC類型
Oracle JVM有5種垃圾收集器,但是在JDK 7以前的版本中,你隻能在Parallel GC, Parallel Compacting GC 和CMS GC之中選擇,至于具體選擇哪個,則沒有具體的原則和規則。
既然這樣的話,我們如何來選擇GC呢?最好的方法是把三種都用上,但是有一點必須明确——CMS GC通常比其他并行(Parallel)GC都要快(這是因為CMS GC是并發的GC),如果确實如此,那隻選擇CMS GC就可以了,不過CMS GC也不總是更快,當出現concurrent mode failure時,CMS GC就會比并行GC更慢了。
Concurrent mode failure
現在讓我們來深入地了解一下concurrent mode failure。
并行GC和CMS GC的最大差別是并行GC采用“标記-整理”(Mark-Compact)算法而CMS GC采用“标記-清除”(Mark-Sweep)算法(具體内容可參照譯者的文章《GC算法與記憶體配置設定政策》),compact步驟就是通過移動記憶體來消除記憶體碎片,進而消除配置設定的記憶體之間的空白區域。
對于并行GC來說,無論何時執行Full GC,都會進行compact工作,這消耗了太多的時間。不過在執行完Full GC後,下次記憶體配置設定将會變得更快(因為直接順序配置設定相鄰的記憶體)。
相反,CMS GC沒有compact的過程,是以CMS GC運作的速度更快。但是也是由于沒有整理記憶體,在進行磁盤清理之前,記憶體中會有很多零碎的空白區域,這也導緻沒有足夠的空間配置設定給大對象。例如,在老年代還有300MB可用空間,但是連一個10MB的對象都沒有辦法被順序存儲在老年代中,在這種情況下,會報出“concurrent mode failure”的warning,然後系統執行compact操作。但是CMS GC在這種情況下執行的compact操作耗時要比并行GC高很多,并且這還會導緻另一個問題,關于“concurrent mode failure”的詳細說明,可用參考Oracle工程師撰寫的《Understanding CMS GC Logs》。
綜上所述,你需要根據你的系統情況為其選擇一個最适合的GC類型。
每個系統都有最适合它的GC類型等着你去尋找,如果你有6台伺服器,我建議你每兩個伺服器設定相同的參數,然後加上
-verbosegc
參數再分析結果。
設定記憶體大小
下面展示了記憶體大小、GC運作次數和GC運作時間之間的關系:
大記憶體空間
- 減少了GC的次數
- 提高了GC的運作時間
小記憶體空間
- 增多了GC的次數
- 降低了GC的運作時間
關于如何設定記憶體的大小,沒有一個标準答案,如果伺服器資源充足并且Full GC能在1s内完成,把記憶體設為10GB也是可以的,但是大部分伺服器并不處在這種狀态中,當記憶體設為10GB時,Full GC會耗時10-30s,具體的時間自然與對象的大小有關。
既然如此,我們該如何設定記憶體大小呢?通常我推薦設為500MB,這不是說你要通過
-Xms500m
-Xmx500m
參數來設定WAS記憶體。根據GC優化之前的狀态,如果Full GC後還剩餘300MB的空間,那麼把記憶體設為1GB是一個不錯的選擇(300MB(預設程式占用)+ 500MB(老年代最小空間)+200MB(空閑記憶體))。這意味着你需要為老年代設定至少500MB空間,是以如果你有三個運作伺服器,可以把它們的記憶體分别設定為1GB,1.5GB,2GB,然後檢查結果。
理論上來說,GC執行速度應該遵循1GB> 1.5GB> 2GB,1GB記憶體時GC執行速度最快。然而,理論上的1GB記憶體Full GC消耗1s、2GB記憶體Full GC消耗2 s在現實裡是無法保證的,實際的運作時間還依賴于伺服器的性能和對象大小。是以,最好的方法是建立盡可能多的測量資料并監控它們。
在設定記憶體空間大小時,你還需要設定一個參數:
NewRatio
NewRatio
的值是新生代和老年代空間大小的比例。如果
XX:NewRatio=1
,則新生代空間:老年代空間=1:1,如果堆記憶體為1GB,則新生代:老年代=500MB:500MB。如果
NewRatio
等于2,則新生代:老年代=1:2,是以,
NewRatio
的值設定得越大,則老年代空間越大,新生代空間越小。
你可能會認為把
NewRatio
設為1會是最好的選擇,然而事實并非如此,根據筆者的經驗,當
NewRatio
設為2或3時,整個GC的狀态表現得更好。
完成GC優化最快地方法是什麼?答案是比較性能測試的結果。為了給每台伺服器設定不同的參數并監控它們,最好檢視的是一或兩天後的資料。當通過性能測試來進行GC優化時,你需要在不同的測試時保證它們有相同的負載和運作環境。然而,即使是專業的性能測試人員,想精确地控制負載也很困難,并且需要大量的時間準備。是以,更加友善容易的方式是直接設定參數來運作,然後等待運作的結果(即使這需要消耗更多的時間)。
分析GC優化的結果
在設定了GC參數和
-verbosegc
參數後,可以使用tail指令確定日志被正确地生成。如果參數設定得不正确或日志未生成,那你的時間就被白白浪費了。如果日志收集沒有問題的話,在收集一或兩天資料後再檢查結果。最簡單的方法是把日志從伺服器移到你的本地PC上,然後用HPJMeter分析資料。
在分析結果時,請關注下列幾點(這個優先級是筆者根據自己的經驗拟定的,我認為選取GC參數時應考慮的最重要的因素是Full GC的運作時間。):
- 單次Full GC運作時間
- 單次Minor GC運作時間
- Full GC運作間隔
- Minor GC運作間隔
- 整個Full GC的時間
- 整個Minor GC的運作時間
- 整個GC的運作時間
- Full GC的執行次數
- Minor GC的執行次數
找到最佳的GC參數是件非常幸運的,然而在大多數時候,我們并不會如此幸運,在進行GC優化時一定要小心謹慎,因為當你試圖一次完成所有的優化工作時,可能會出現
OutOfMemoryError
錯誤。
## 優化案例
到目前為止,我們一直在從理論上介紹GC優化,現在是時候将這些理論付諸實踐了,我們将通過幾個例子來更深入地了解GC優化。
示例1
下面這個例子是針對Service S的優化,對于最近剛開發出來的Service S,執行Full GC需要消耗過多的時間。
現在看一下執行
jstat -gcutil
的結果
S0 S1 E O P YGC YGCT FGC FGCT GCT
12.16 0.00 5.18 63.78 20.32 54 2.047 5 6.946 8.993
左邊的Perm區的值對于最初的GC優化并不重要,而YGC參數的值更加對于這次優化更為重要。
平均執行一次Minor GC和Full GC消耗的時間如下表所示:
表3:Service S的Minor GC 和Full GC的平均執行時間
GC執行次數 | GC執行時間 | 平均值 | |
---|---|---|---|
Minor GC | 54 | 2.047s | 37ms |
Full GC | 5 | 6.946s | 1.389s |
37ms對于Minor GC來說還不賴,但1.389s對于Full GC來說意味着當GC發生在資料庫Timeout設定為1s的系統中時,可能會頻繁出現逾時現象。
首先,你需要檢查開始GC優化前記憶體的使用情況。使用
jstat -gccapacity
指令可以檢查記憶體用量情況。在筆者的伺服器上檢視到的結果如下:
NGCMN NGCMX NGC S0C S1C EC OGCMN OGCMX OGC OC PGCMN PGCMX PGC PC YGC FGC
212992.0 212992.0 212992.0 21248.0 21248.0 170496.0 1884160.0 1884160.0 1884160.0 1884160.0 262144.0 262144.0 262144.0 262144.0 54 5
其中的關鍵值如下:
- 新生代記憶體用量:212,992 KB
- 老年代記憶體用量:1,884,160 KB
是以,除了永久代以外,被配置設定的記憶體空間加起來有2GB,并且新生代:老年代=1:9,為了得到比使用
jstat
更細緻的結果,還需加上
-verbosegc
參數擷取日志,并把三台伺服器按照如下方式設定(除此以外沒有使用任何其他參數):
- NewRatio=2
- NewRatio=3
- NewRatio=4
一天後我得到了系統的GC log,幸運的是,在設定完NewRatio後系統沒有發生任何Full GC。
這是為什麼呢?這是因為大部分對象在建立後很快就被回收了,所有這些對象沒有被傳入老年代,而是在新生代就被銷毀回收了。
在這樣的情況下,就沒有必要去改變其他的參數值了,隻要選擇一個最合适的
NewRatio
值即可。那麼,如何确定最佳的NewRatio值呢?為此,我們分析一下每種
NewRatio
值下Minor GC的平均響應時間。
在每種參數下Minor GC的平均響應時間如下:
- NewRatio=2:45ms
- NewRatio=3:34ms
- NewRatio=4:30ms
我們可以根據GC時間的長短得出NewRatio=4是最佳的參數值(盡管NewRatio=4時新生代空間是最小的)。在設定完GC參數後,伺服器沒有發生Full GC。
為了說明這個問題,下面是服務執行一段時間後執行
jstat –gcutil
的結果:
S0 S1 E O P YGC YGCT FGC FGCT GCT
8.61 0.00 30.67 24.62 22.38 2424 30.219 0 0.000 30.219
你可能會認為是伺服器接收的請求少才使得GC發生的頻率較低,實際上,雖然Full GC沒有執行過,但Minor GC被執行了2424次。
示例2
這是一個Service A的例子。我們通過公司内部的應用性能管理系統(APM)發現JVM暫停了相當長的時間(超過8秒),是以我們進行了GC優化。我們努力尋找JVM暫停的原因,後來發現是因為Full GC執行時間過長,是以我們決定進行GC優化。
在GC優化的開始階段,我們加上了
-verbosegc
參數,結果如下圖所示:

圖1:進行GC優化之前STW的時間
上圖是由HPJMeter生成的圖檔之一。橫坐标表示JVM執行的時間,縱坐标表示每次GC的時間。CMS為綠點,表示Full GC的結果,而Parallel Scavenge為藍點,表示Minor GC的結果。
之前我說過CMS GC是最快的GC,但是上面的結果顯示在一些時候CMS耗時達到了15s。是什麼導緻了這一結果?請記住我之前說的:CMS在執行compact(整理)操作時會顯著變慢。此外,服務的記憶體通過
-Xms1g
=Xmx4g
設定了,而配置設定的記憶體隻有4GB。
是以筆者将GC類型從CMS GC改為了Parallel GC,把記憶體大小設為2GB,并把
NewRatio
設為3。在執行
jstat -gcutil
幾小時後的結果如下:
S0 S1 E O P YGC YGCT FGC FGCT GCT
0.00 30.48 3.31 26.54 37.01 226 11.131 4 11.758 22.890
Full GC的時間縮短了,變成了每次3s,跟15s比有了顯著提升。但是3s依然不夠快,為此筆者建立了以下6種情況:
- Case 1:
-XX:+UseParallelGC -Xms1536m -Xmx1536m -XX:NewRatio=2
- Case 2:
-XX:+UseParallelGC -Xms1536m -Xmx1536m -XX:NewRatio=3
- Case 3:
-XX:+UseParallelGC -Xms1g -Xmx1g -XX:NewRatio=3
- Case 4:
-XX:+UseParallelOldGC -Xms1536m -Xmx1536m -XX:NewRatio=2
- Case 5:
-XX:+UseParallelOldGC -Xms1536m -Xmx1536m -XX:NewRatio=3
- Case 6:
-XX:+UseParallelOldGC -Xms1g -Xmx1g -XX:NewRatio=3
上面哪一種情況最快?結果顯示,記憶體空間越小,運作結果最少。下圖展示了性能最好的Case 6的結果圖,它的最慢響應時間隻有1.7s,并且響應時間的平均值已經被控制到了1s以内。
圖2:Case 6的持續時間圖
基于上圖的結果,按照Case 6調整了GC參數,但這卻導緻每晚都會發生
OutOfMemoryError
。很難解釋發生異常的具體原因,簡單地說,應該是批處理程式導緻了記憶體洩漏,我們正在解決相關的問題。
如果隻對GC日志做一些短時間的分析就将相關參數部署到所有伺服器上來執行GC優化,這将是非常危險的。切記,隻有當你同時仔細分析服務的執行情況和GC日志後,才能保證GC優化沒有錯誤地執行。
在上文中,我們通過兩個GC優化的例子來說明了GC優化是怎樣執行的。正如上文中提到的,例子中設定的GC參數可以設定在相同的伺服器之上,但前提是他們具有相同的CPU、作業系統、JDK版本并且運作着相同的服務。此外,不要把我使用的參數照搬到你的應用上,它們可能在你的機器上并不能起到同樣良好的效果。
總結
筆者沒有執行heap dump并分析記憶體的詳細内容,而是通過自己的經驗進行GC優化。精确地分析記憶體可以得到更好的優化效果,不過這種分析一般隻适用于記憶體使用量相對固定的場景。如果服務嚴重過載并占有了大量的記憶體,則建議你根據之前的經驗進行GC優化。
筆者已經在一些服務上設定了G1 GC參數并進行了性能測試,但還沒有應用于正式的生産環境。G1 GC的速度快于任何其他的GC類型,但是你必須要更新到JDK 7。此外,暫時還無法保證它的穩定性,沒有人知道運作時是否會出現緻命的錯誤,是以G1
GC暫時還不适合投入應用。
等未來JDK 7真正穩定了(這并不是說它現在不穩定),并且WAS針對JDK 7進行優化後,G1 GC最終能按照預期的那樣來工作,等到那一天我們可能就不再需要GC優化了。
想了解關于GC優化的更多細節,請前往Slideshare.com 檢視相關資料。強烈推薦Everything I Ever Learned About JVM Performance Tuning @Twitter,作者是Attila Szegedi, 一名Twitter工程師,請花些時間好好閱讀它。
作者:純潔的微笑
出處:www.ityouknow.com
資源:微信搜【純潔的微笑】關注我,回複 【程式員】【面試】【架構師】有我準備的一線程式必備計算機書籍、大廠面試資料和免費電子書。 一共1024G的資料,希望可以幫助大家提升技術和能力。
本文如對您有幫助,還請多幫 【推薦】 下此文。
點我了解:Tooool-程式員一站式導航網站