天天看點

關于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區。如下圖:

關于JAVA中記憶體溢出的解決辦法

關于個分區的用途,大家可以參考其他相關文檔。本教程所要處理的問題是如何解決記憶體溢出的問題。接下來以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 就會彈出三個可見視圖。

如下圖:

關于JAVA中記憶體溢出的解決辦法

參考資料《淺談SUNJVM 記憶體管理與應用伺服器的優化之SUNJVM 記憶體管理》JasonS.H.Chen

參考資料《淺談SUNJVM 記憶體管理與應用伺服器的優化之伺服器記憶體配置設定與優化》JasonS.H.Chen