關於JAVA中內存溢出的解決辦法

關於JAVA中內存溢出的解決辦法

J2ee應用系統是運行在J2EE應用服務器上的,而j2ee應用服務器又是運行在JVM上的,

生成環境中JVM參數的優化和設置對於J2EE應用系統性能有着決定性的作用。要優化系統,則需要對JVM參數進行合理的設置,所以我們需要了解究竟在什麼地方進行設置、有哪些參數以及各參數的意義分別是什麼,並且我們還得了解JVM的內存管理機制究竟是個什麼玩意兒?其實我們在網上搜索引擎上,一搜就有可以獲取到一大把相關信息,關鍵是我們如何深入的理解它們。那麼下面我們就簡單的介紹一下究竟什麼是JVM的內存管理機制吧~!  

 

JVM的早期版本並沒有進行分區管理;這樣的後果是JVM進行垃圾回收時,不得不掃描JVM所管理的整片內存,所以蒐集垃圾是很耗費資源的事情,也是早起JAVA程序的性能低下的主要原因。隨着JVM的發展,JVM引進了分區管理的機制。

 

JVM所管理的所有內存資源分爲2個大的部分。永久存儲區(Permanent Space) 和堆空間(The Heap Space)。其中對空間又分爲新生區()和養老區,新生區又分爲伊甸園,倖存者0區、倖存1區。如下圖:

 

關於個分區的用途,大家可以參考其他相關文檔。本教程所要處理的問題是如何解決內存溢出的問題。接下來以tomcat服務器爲例:

我們首先得找到內存管理所要設置的參數在哪個文件:<CATALINA_HOME>/bin/catalina.bat。

需要添加一行代碼:

JAVA_OPTS="-Xms512m-Xmx512m -Xss1024K -XX:PermSize=256m -XX:MaxPermSize=256m"

下面分別對各參數進行介紹和解釋:

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 對內存資源的使用,不會充分的利用所有的內存資源。

 

 

 

結論:“永久存儲區溢出(java.lang.OutOfMemoryError:Java Permanent Space)”乃是永久存儲區設置太小,不能滿足系統需要的大小,此時只需要調整-XX:PermSize 和-XX:MaxPermSize 這兩個參數即可。“JVM 堆空間溢出(java.lang.OutOfMemoryError: Java heap space)”錯誤是JVM 堆空間不足,此時只需要調整-Xms 和-Xmx 這兩個參數即可。

 

 

 

到此我們知道了,當系統出現內存溢出時,是哪些參數設置不合理需要調整。但我們怎麼知道服務器啓動時,到底JVM 內存相關參數的值是多少呢?

這個問題其實Sun公司早已經意料到了,所以給我們開發了內存使用監控工具jvmstat.

大家可以到ORACLE官網進行下載。用它可以很方便的看到我們的服務器內存使用情況。

將下載的jvmstat包解壓到如“C:\ProgramFiles\Java\jvmstat”(這是我本地java路徑,大家可以根據自己所安裝的java環境的路徑進行解壓)。啓動完之後我們就可以使用visualgc命令了,cmd進入命令符窗口,輸入tasklist(windows下查看進程任務PID)查找到你要檢測進程PID.然後直接輸入visuglgc PID 就會彈出三個可見視圖。

如下圖:

 

 

 

 

 

 

參考資料《淺談SUNJVM 內存管理與應用服務器的優化之SUNJVM 內存管理》JasonS.H.Chen

發佈了16 篇原創文章 · 獲贊 3 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章