作者:Jason S.H.Chen
上篇給大家介紹了SUN JVM的內存管理機制。本篇主要講解與性能相關的JVM參數,怎樣使用工具監控JVM的內存分配使用情況和怎樣調整JVM參數讓系統在特定硬件配置下達到最優化的性能。
通過上篇SUN JVM內存管理機制的介紹,大家都知道了SUN JVM內存分為永久存儲區,伊甸園,幸存者1區,幸存者2區和養老區等幾個區域。他們的作用以及垃圾回收處理過程在上篇也做了詳細介紹。下面我們就來看看和這些內存分區相關的JVM參數。
JVM相關參數:
參數名 參數說明
-server 啟用能夠執行優化的編譯器, 顯著提高服務器的性能,但使用能夠執行優化的編譯器時,服務器的預備時間將會較長。生產環境的服務器強烈推薦設置此參數。
-Xss 單個線程堆棧大小值;JDK5.0以后每個線程堆棧大小為1M,以前每個線程堆棧大小為256K。在相同物理內存下,減小這個值能生成更多的線程。但是操作系統對一個進程內的線程數還是有限制的,不能無限生成,經驗值在3000~5000左右。
-XX:+UseParNewGC
可用來設置年輕代為并發收集【多CPU】,如果你的服務器有多個CPU,你可以開啟此參數;開啟此參數,多個CPU可并發進行垃圾回收,可提高垃圾回收的
速度。此參數和+UseParallelGC,-XX:ParallelGCThreads搭配使用。
+UseParallelGC 選擇垃圾收集器為并行收集器。此配置僅對年輕代有效。即上述配置下,年輕代使用并發收集,而年老代仍舊使用串行收集 。可提高系統的吞吐量。
-XX:ParallelGCThreads 年輕代并行垃圾收集的前提下(對并發也有效果)的線程數,增加并行度,即:同時多少個線程一起進行垃圾回收。此值最好配置與處理器數目相等。
永久存儲區相關參數:
參數名 參數說明
-Xnoclassgc 每次永久存儲區滿了后一般GC算法在做擴展分配內存前都會觸發一次FULL GC,除非設置了-Xnoclassgc.
-XX:PermSize 應用服務器啟動時,永久存儲區的初始內存大
-XX:MaxPermSize 應用運行中,永久存儲區的極限值。為了不消耗擴大JVM永久存儲區分配的開銷,將此參數和-XX:PermSize這個兩個值設為相等。
堆空間相關參數
參數名 參數說明
-Xms 啟動應用時,JVM堆空間的初始大小值。
-Xmx 應用運行中,JVM堆空間的極限值。為了不消耗擴大JVM堆控件分配的開銷,將此參數和-Xms這個兩個值設為相等,考慮到需要開線程,講此值設置為總內存的80%.
-Xmn 此參數硬性規定堆空間的新生代空間大小,推薦設為堆空間大小的1/4。
上面所列的JVM參數關系到系統的性能,而其中-XX:PermSize,-XX:MaxPermSize,-Xms,-Xmx和-Xmn這5個參數更是直接關系到系統的性能,系統是否會出現內存溢出。
-XX:PermSize和-XX:MaxPermSize分別設置應用服務器啟動時,永久存儲區的初始大小和極限大小;在生成環境中強烈推薦將
這個兩個值設置為相同的值,以避免分配永久存儲區的開銷,具體的值可取系統“疲勞測試”獲取到的永久存儲區的極限值;如果不進行設置
-XX:MaxPermSize默認值為64M,一般來說系統的類定義文件大小都會超過這個默認值。
-Xms和-Xmx分別是服務器啟動時,堆空間的初始大小和極限值。-Xms的默認值是物理內存的1/64但小于1G,-Xmx的默認值是物理
內存的1/4但小于1G.在生產環境中這些默認值是肯定不能滿足我們的需要的。也就是你的服務器有8g的內存,不對JVM參數進行設置優化,應用服務器啟
動時還是按默認值來分配和約束JVM對內存資源的使用,不會充分的利用所有的內存資源。
到此我們就不難理解上文提到的“我的服務器有8g內存,系統也就100M左右,居然出現內存溢出”這個“怪現象”了。在上文我曾提到“永久存儲
區溢出(java.lang.OutOfMemoryError: Java Permanent
Space)”和“JVM堆空間溢出(java.lang.OutOfMemoryError: Java heap
space)”這兩種溢出錯誤。現在大家都知道答案了:“永久存儲區溢出(java.lang.OutOfMemoryError: Java
Permanent
Space)”乃是永久存儲區設置太小,不能滿足系統需要的大小,此時只需要調整-XX:PermSize和-XX:MaxPermSize這兩個參數即
可。“JVM堆空間溢出(java.lang.OutOfMemoryError: Java heap
space)”錯誤是JVM堆空間不足,此時只需要調整-Xms和-Xmx這兩個參數即可。
到此我們知道了,當系統出現內存溢出時,是哪些參數設置不合理需要調整。但我們怎么知道服務器啟動時,到底JVM內存相關參數的值是多少呢。在
實踐中,經常遇到對JVM參數進行設置了,并且自己心里覺得應該不會出現內存溢出了;但不幸的是內存溢出還是發生了。很多人百思不得其解,那我可以肯定地
告訴你,你設置的JVM參數并沒有起作用(本文咱不探討沒有起作用的原因)。不信我們就去看看,下面介紹如何使用SUN公司的內存使用監控工具
jvmstat.
本文只介紹如何使用jvmstat查看內存使用,不介紹其安裝配置。有興趣的讀者,可到SUN公司的官方網站下載一個,他本身已經帶有非常詳細
的安裝配置文檔了。這里假設你已經在你的應用服務器上配置好了jvmstat了。那我們就開始使用他來看看我們的服務器到底是有沒有按照我們設置的參數啟
動。
首先啟動服務器,等服務器啟動完。開啟DOS窗口(此例子是在windows下完成,linux下同樣),在dos窗口中輸入jps這個命令。如下圖
窗口中會顯示所有JAVA應用進程列表,列表的第一列為應用的進程ID,第二列為應用的名字。在列表中找到你的應用服務器的進程ID,比如我這里的應用服務器進程ID為1856.在命令行輸入visualgc 1856回車。進入jvmstat的主界面,如下圖:
上圖分別標注了伊甸園,幸存者0區,幸存者1區,養老區和永久存儲區。圖上直觀的反應出各存儲區的大小,已經使用的大小,剩下的空間大小,并用數
字標出了各區的大小;如果你這上面的數字和你設置的JVM參數相同的話,那么恭喜你,你設置的參數已經起作用,如果和你設置的不一致的話,那么你設置的參
數沒有起作用(可能是服務器的啟動方式沒有載入你的JVM參數設置。)
在優化服務器的時候,這個工具很有用,他占用資源少。可以隨應用服務器一直保持開啟狀態,如果系統發生內粗溢出,可以一眼就看出是那個區發生了溢出。根據觀察結果進行進一步優化。