本文將為您提供5個技巧,這些技巧可以幫助您確定當前或新生產環境的最佳Java堆大小。 這些技巧中的一些對于預防和解決java.lang.OutOfMemoryError問題也非常有用。 包括內存泄漏。
請注意,這些技巧旨在“幫助您”確定適當的Java堆大小。 由于每個IT環境都是唯一的,因此您實際上處于最佳位置,可以精確地確定客戶端環境所需的Java Heap規范。 其中一些技巧可能也不適用于非常小的Java獨立應用程序,但是我仍然建議您閱讀整篇文章。
未來的文章將包含有關如何為您的環境和應用程序選擇正確的Java VM垃圾收集器類型的提示。
#1 – JVM:您總是擔心自己不了解的內容
您如何期望對您不了解的內容進行配置,調整和故障排除? 您可能永遠沒有機會編寫和改進Java VM規范,但是您仍然可以自由學習它的基礎,以提高您的知識和故障排除技能。 有些人可能會不同意,但是從我的角度來看,認為Java程序員不需要了解內部JVM內存管理的想法是一種幻想。
對于Java和Java EE初學者來說,Java Heap調優和故障排除尤其是一項挑戰。 在以下典型情況下查找:
–您的客戶端生產環境經常面臨OutOfMemoryError并造成大量業務影響。 您的支持團隊承受著解決此問題的壓力
–通過Google的快速搜索,您可以找到類似問題的示例,現在您認為(并假設)自己面臨相同的問題
–然后抓取JVM -Xms和 -Xmx值來自另一個人的OutOfMemoryError問題案例,希望能快速解決客戶的問題 –然后,繼續對您的環境實施相同的調整。 2天后,您意識到問題仍在發生(甚至更糟或稍好一點)……斗爭仍在繼續……
什么地方出了錯?
–您首先沒有正確了解問題的根本原因
–您可能還沒有從更深層次上正確地了解您的生產環境(規格,負載情況等)。 網絡搜索是學習和共享知識的好方法,但您必須執行自己的盡職調查和根本原因分析 –您可能還缺少一些有關JVM及其內部內存管理的基本知識,從而使您無法將所有點連接在一起
我給您的#1技巧和建議是學習和理解JVM的基本原理及其不同的內存空間。 這些知識很關鍵,因為它將使您能夠向客戶提出有效建議,并正確理解與將來的調整注意事項相關的可能影響和風險。 現在,在下面找到有關Java VM的快速高級參考指南:
Java VM內存最多分為3個內存空間:
- Java堆 。 適用于所有JVM供應商,通常在YoungGen(苗圃)和OldGen(租用)空間之間劃分。
- PermGen (永久代)。 僅適用于Sun HotSpot VM(PermGen空間將在以后的Java 7或Java 8更新中刪除 )
- 本機堆 (C-Heap)。 適用于所有JVM供應商。

我建議您閱讀以下每篇文章,包括有關HotSpot Java內存管理的Sun白皮書。 我也鼓勵您下載并查看OpenJDK實現。
## Sun HotSpot VM http://javaeesupportpatterns.blogspot.com/2011/08/java-heap-space-hotspot-vm.html
## IBM VM http://javaeesupportpatterns.blogspot.com/2012/02/java-heap-space-ibm-vm.html
## Oracle JRockit VM http://javaeesupportpatterns.blogspot.com/2012/02/java-heap-space-jrockit-
vm.html
## Sun(Oracle)– Java內存管理白皮書 http://java.sun.com/j2se/reference/whitepapers/memorymanagement_whitepaper.pdf
## OpenJDK –開源Java實現 http://openjdk.java.net/
如您所見,Java VM內存管理比通過–Xmx設置可能的最大值要復雜得多。 您必須從各個角度考慮問題,包括您的本機和PermGen空間要求以及來自物理主機的物理內存可用性(和CPU內核數量)。
由于Java Heap和本機Heap處于競爭之中,因此對于32位JVM來說,它尤其棘手。 Java堆越大,本機堆越小。 嘗試為32位VM(例如.2.5 GB +)設置較大的堆會增加本機OutOfMemoryError的風險,具體取決于您的應用程序占用空間,線程數等。64位JVM解決了此問題,但您仍然限于物理資源可用性和垃圾收集開銷(大型GC收集的成本隨大小而增加)。 最重要的是,越大并不總是越好,因此請不要假定您可以在單個16 GB 64位JVM進程上運行所有20個Java EE應用程序。
#2 –數據和應用程序為王:查看您的靜態占用空間要求
您的應用程序及其關聯數據將指示Java Heap占用空間要求。 靜態內存是指“可預測的”內存需求,如下所示。
–確定要計劃部署到單個JVM進程的多少個不同的應用程序,例如EAR文件,WAR文件,jar文件的數量。您部署到單個JVM的應用程序越多,對本機堆的需求就越高
–確定在運行時可能會加載多少個Java類; 包括第三方API。 您在運行時加載的類加載器和類越多,對HotSpot VM PermGen空間和與內部JIT相關的優化對象的需求就越高 –確定數據緩存占用空間,例如由應用程序(和第三方API)加載的內部緩存數據結構,例如從數據庫緩存的數據,從文件讀取的數據等。您使用的數據緩存越多,對Java Heap OldGen的需求就越高空間 –確定允許您的中間件創建的線程數。 這非常重要,因為Java線程需要足夠的本機內存,否則將引發OutOfMemoryError。
例如,如果您打算在單個JVM進程上部署10個單獨的EAR應用程序,而不是2個或3個,則將需要更多的本機內存和PermGen空間。未序列化到磁盤或數據庫的數據緩存將需要從磁盤上獲得額外的內存。 OldGen空間。
嘗試合理估計靜態內存占用量。 在進行真正的測量練習之前,這對于設置一些起點JVM容量數字非常有用(例如,技巧4)。 對于32位JVM,我通常不建議Java Heap大小大于2 GB(-Xms2048m,-Xmx2048m),因為您需要足夠的內存用于PermGen,并需要足夠的Java EE應用程序和線程本機堆。
此評估尤為重要,因為在單個32位JVM進程中部署的應用程序過多,很容易導致本機堆耗盡。 特別是在多線程環境中。
對于64位JVM,通常建議每個Java進程3 GB或4 GB的Java堆大小。
#3 –商業流量設定規則:查看您的動態足跡需求
您的業??務流量通常會決定您的動態內存占用量。 并發用戶和請求會生成JVM GC“心跳”,由于頻繁創建和廢棄短期和長期存在的對象,您可以從各種監視工具中觀察到它們。 從上面的JVM圖表中可以看到,YoungGen與OldGen的典型比率是1:3或33%。
對于典型的32位JVM,Java Heap大小設置為2 GB(使用分代和并發收集器)通常將為YoungGen空間分配500 MB,為OldGen空間分配1.5 GB。
最小化主要GC收集的頻率是獲得最佳性能的關鍵方面,因此,了解并估算峰值量期間需要多少內存非常重要。
同樣,您的應用程序和數據類型將決定您需要多少內存。 涉及大型和非序列化會話數據的購物車類型的應用程序(壽命長的對象)通常需要大型Java堆和大量OldGen空間。 無狀態和XML處理繁重的應用程序(很多短期對象)需要適當的YoungGen空間,以最大程度地減少主要集合的頻率。
例:
–您要部署5個EAR應用程序(約2000個Java類)(還包括中間件代碼…)
–您的本機堆需求估計為1 GB(必須足夠大以處理線程創建等)–您的PermGen空間估計為512 MB
–內部靜態數據緩存估計為500 MB –在高峰時段,您的總預測流量為5000個并發用戶 –每個用戶會話數據占用量估計為500 K –僅會話數據所需的總占用空間為峰值容量以下的2.5 GB
如您所見,根據這種要求,您不可能將所有這些流量發送到單個JVM 32位進程。 一個典型的解決方案涉及在幾個JVM進程和/或物理主機之間分配流量(技巧5)(假設您有足夠的可用硬件和CPU內核)。
但是,對于此示例,由于對靜態內存的需求很高,并且從長遠來看要確保可擴展的環境,我還建議您使用64位VM,但是以較小的Java Heap作為起點,例如3 GB,以最大程度地減少GC成本。 您絕對希望為OldGen空間留出額外的緩沖區,因此我通常建議在大型采集后最多保留50%的內存,以保持Full GC的頻率較低,并為故障轉移方案提供足夠的緩沖區。
在大多數情況下,除非您需要大量的數據緩存以實現適當的性能(這對于門戶(媒體)繁重的應用程序是典型的),否則業務流量將占用您的大部分內存。 太多的數據緩存會產生一個黃色標記,您可能需要早于稍后重新訪問某些設計元素。
#4 –不要猜測,要衡量!
此時,您應該:
–了解基本的JVM原理和內存空間
–對所有應用程序及其特征(大小,類型,動態流量,無狀態對象與有狀態對象,內部內存緩存等)有深入的了解和了解。
–對每個應用程序的業務流量(并發用戶數等)以及每個應用程序都具有很好的視圖或預測–如果需要是否需要64位VM以及從哪個JVM設置開始,可以有一些想法 –一些想法,如果您需要多個JVM(中間件)進程
但是,等等,您的工作尚未完成。 盡管以上信息至關重要,并且對您提出“最佳猜測” Java Heap設置非常有用,但它始終是最好的,建議您通過適當的性能分析,加載和性能模擬應用程序行為并驗證Java Heap內存需求測試。
您可以學習和利用JProfiler之類的工具(未來的文章將包括有關JProfiler的教程)。 從我的角度來看,學習如何使用事件探查器是正確了解應用程序內存占用量的最佳方法。 我用于現有生產環境的另一種方法是使用Eclipse MAT工具進行堆轉儲分析。 堆轉儲分析功能非常強大,它使您可以查看和了解Java Heap的整個內存占用量,包括與類加載器相關的數據,并且在任何內存占用量分析中都必須進行此練習。 特別是內存泄漏。

Java分析器和堆轉儲分析工具使您能夠了解和驗證應用程序的內存占用量,包括檢測和解決內存泄漏。 負載和性能測試也是必須的,因為這將允許您通過模擬預測的并發用戶來驗證較早的估計。 它還將暴露您的應用程序瓶頸,并允許您進一步微調JVM設置。 您可以使用諸如Apache JMeter之類的工具,這些工具非常易于學習和使用,也可以探索其他商業產品。
最后,我經常看到Java EE環境運行良好,直到基礎架構的一部分開始出現故障(例如硬件故障)為止。 突然,環境以減少的容量運行(JVM進程的數量減少),并且整個環境崩潰了。 發生了什么?
有許多情況可能導致多米諾骨牌效應,但是JVM調優和處理故障轉移 (短期額外負載)的能力非常普遍。 如果您的JVM進程以80%+的OldGen空間容量運行并且具有頻繁的垃圾回收,那么您如何期望處理任何故障轉移方案?
前面執行的負載和性能測試練習應該模擬這種情況,并且應該適當地調整調整設置,以便Java Heap有足夠的緩沖區來在短期內處理額外的負載(額外的對象)。 這主要適用于動態內存占用量,因為故障轉移意味著將一定百分比的并發用戶重定向到可用的JVM進程(中間件實例)。
#5 –分而治之
至此,您已經執行了數十次負載測試迭代。 您知道您的JVM不會泄漏內存。 您的應用程序內存占用空間無法再減少。 您嘗試了幾種調優策略,例如使用10 GB +的大型64位Java堆空間,多個GC策略,但仍然找不到可接受的性能級別?
根據我的經驗,我發現,在當前的JVM規范下,適當的垂直和水平擴展會涉及為每個物理主機以及跨多個主機創建幾個JVM進程,從而為您提供所需的吞吐量和容量。 如果將您的應用程序列表分為幾個邏輯孤島(具有各自的JVM進程,線程和調整值),則您的IT環境也將具有更高的容錯能力。
這種“分而治之”的策略涉及將您的應用程序流量拆分到多個JVM進程,并將為您提供:
–減少了每個JVM進程的Java堆大小(靜態和動態覆蓋)
–降低了JVM調整的復雜性
–減少了每個JVM進程的GC經過和暫停時間 –增強的冗余和故障轉移功能 –與最新的云和IT虛擬化策略保持一致
最重要的是,當您發現自己花費太多時間來調整單個大象的64位JVM進程時,就該重新審視您的中間件和JVM部署策略并利用縱向和橫向擴展優勢了。 這種實施策略對硬件的負擔更大,但從長遠來看確實會有所回報。
請提供任何評論,并分享您對JVM Heap調整大小和調整的經驗。
參考: Java EE支持模式和Java教程博客中的JCG合作伙伴 Pierre-Hugues Charbonneau提供了5個有關適當的Java堆大小的技巧 。
翻譯自: https://www.javacodegeeks.com/2012/07/5-tips-for-proper-java-heap-size.html