1. 程式人生 > >Java學習路線指南之JVM調優並解決OutOfMemoryError,StackOverflowError

Java學習路線指南之JVM調優並解決OutOfMemoryError,StackOverflowError

 JVM 調優,首先應從記憶體開始,尤其是在真正的的web服務部署的時候。因為真正的web服務會比開發的時候花費更多的記憶體,用來處理多使用者併發的情況。本人多次吃過這方面的虧,所以整理一下,希望能給別人以幫助。

 

       這個年頭變啦,記憶體變得如大白菜,每個新裝的機器都2G以上的記憶體,甚至4G,也不是什麼新聞。而軟體‘吃’記憶體的情況則變化不大(除了VIsta)。但 JAVA誕生的時候可不是這樣——95年,想來當年97年,64M的記憶體還要500元,所以JVM初始化對記憶體的要不能太大,而且也要考慮老機器的情況,畢竟現在JRE基本跑在每個人的機器上。但是JVM初始佔用還停留在幾年前的情況下,確實沒有跟上軟體和硬體的發展。而像Tomcat, JBoss, Eclipse(尤其安上MyEclipse外掛後),也考慮到每臺機器的記憶體情況,所以初始話定義都很低,經常會拋記憶體溢位Bug。

 

    好,言歸正傳。我們先從解決bug開始,當Java程式申請記憶體,超出VM可分配內純的時候,VM首先可能會GC,如果GC完還是不夠,或者申請的直接超夠VM可能有的,就會丟擲記憶體溢位異常。從VM規範中我們可以得到,一下幾種異常。

 

     java.lang.StackOverflowError:(很少)

     java.lang.OutOfMemoryError:heap space(比較常見)

     java.lang.OutOfMemoryError: PermGen space (經常出現)

 

   以下分別解釋一下,從最常見的開始:

 

       java.lang.OutOfMemoryError: PermGen space 這個異常比較常見,是說JVM裡的Perm記憶體區的異常溢位,由於JVM在預設的情況下,Perm預設為64M,而很多程式需要大量的Perm區記憶體,尤其使用到像Spring等框架的時候,由於需要使用到動態生成類,而這些類不能被GC自動釋放,所以導致OutOfMemoryError: PermGen space異常。解決方法很簡單,增大JVM的 -XX:MaxPermSize 啟動引數,就可以解決這個問題,如過使用的是預設變數通常是64M[5.0 and newer: 64 bit VMs are scaled 30% larger; 1.4 amd64: 96m; 1.3.1 -client: 32m.],改成128M就可以了,-XX:MaxPermSize=128m。如果已經是128m(Eclipse已經是128m了),就改成 256m。我一般在伺服器上為安全起見,改成256m。

 

     java.lang.OutOfMemoryError:heap space或 其它OutOfMemoryError,這個異常實際上跟上面的異常是一個異常,但解決方法不同,所以分開來寫。上面那個異常是因為JVM的perm區記憶體區分少了引起的(JVM的記憶體區分為 young,old,perm三種)。而這個異常是因為JVM堆記憶體或者說總體分少了。解決方法是更改 -Xms -Xmx 啟動引數,通常是擴大1倍。xms是管理啟動時最小記憶體量的,xmx是管裡JVM最大的記憶體量的。

    注:OutOfMemoryError可能有很多種原因,根據JVM Specification, 可能有一下幾種情況,我先簡單列出。stack:stack分割槽不能動態擴充套件,或不足以生成新的執行緒。Heap:需要更多的記憶體,而不能獲得。Method Area :如果不能滿足分配需求。runtime constant pool(從Method Area分配記憶體)不足以建立class or interface。native method stacks不能夠動態擴充套件,或生成新的本地執行緒。

 

    最後說說java.lang.StackOverflowError,老實說這個異常我也沒碰見過,但JVM Specification就提一下,規範上說有一下幾種境況可能丟擲這個異常,一個是Stacks裡的執行緒超過允許的時候,另一個是當native method要求更大的記憶體,而超過native method允許的記憶體的時候。根據SUN的文件,提高-XX:ThreadStackSize=512的值。

 

    總的來說調優JVM的記憶體,組要目的就是在使用記憶體儘可能小的,使程式執行正常,不丟擲內純溢位的bug。而且要調好最小記憶體,最大記憶體的比,避免GC時浪費太多時間,尤其是要儘量避免FULL GC。