1. 程式人生 > >Java中OutOfMemoryError(記憶體溢位)的三種情況及解決辦法

Java中OutOfMemoryError(記憶體溢位)的三種情況及解決辦法

相信有一定java開發經驗的人或多或少都會遇到OutOfMemoryError的問題,這個問題曾困擾了我很長時間,隨著解決各類問題經驗的積累以及對問題根源的探索,終於有了一個比較深入的認識。

在解決java記憶體溢位問題之前,需要對jvm(java虛擬機器)的記憶體管理有一定的認識。jvm管理的記憶體大致包括三種不同型別的記憶體區域:PermanentGeneration space(永久儲存區域)、Heap space(堆區域)、JavaStacks(Java棧)。其中永久儲存區域主要存放Class(類)和Meta的資訊,Class第一次被Load的時候被放入PermGenspace區域,Class需要儲存的內容主要包括方法和靜態屬性。堆區域用來存放Class的例項(即物件),物件需要儲存的內容主要是非靜態屬性。每次用new建立一個物件例項後,物件例項儲存在堆區域中,這部分空間也被jvm的垃圾回收機制管理。而Java棧跟大多數程式語言包括組合語言的棧功能相似,主要基本型別變數以及方法的輸入輸出引數。Java程式的每個執行緒中都有一個獨立的堆疊。容易發生記憶體溢位問題的記憶體空間包括:PermanentGeneration space和Heap space。

第一種OutOfMemoryError: PermGenspace
發生這種問題的原意是程式中使用了大量的jar或class,使java虛擬機器裝載類的空間不夠,與PermanentGeneration space有關。解決這類問題有以下兩種辦法:
1.增加java虛擬機器中的XX:PermSize和XX:MaxPermSize引數的大小,其中XX:PermSize是初始永久儲存區域大小,XX:MaxPermSize是最大永久儲存區域大小。如針對tomcat6.0,在catalina.sh或catalina.bat檔案中一系列環境變數名說明結束處(大約在70行左右) 增加一行:
JAVA_OPTS=" -XX:PermSize=64M -XX:MaxPermSize=128m"
如果是windows伺服器還可以在系統環境變數中設定。感覺用tomcat釋出sprint+struts+hibernate架構的程式時很容易發生這種記憶體溢位錯誤。使用上述方法,我成功解決了部署ssh專案的tomcat伺服器經常宕機的問題。
2.清理應用程式中web-inf/lib下的jar,如果tomcat部署了多個應用,很多應用都使用了相同的jar,可以將共同的jar移到tomcat共同的lib下,減少類的重複載入。這種方法是網上部分人推薦的,我沒試過,但感覺減少不了太大的空間,最靠譜的還是第一種方法。

第二種OutOfMemoryError: Java heap space

發生這種問題的原因是java虛擬機器建立的物件太多,在進行垃圾回收之間,虛擬機器分配的到堆記憶體空間已經用滿了,與Heapspace有關。解決這類問題有兩種思路:
1. 檢查程式,看是否有死迴圈或不必要地重複建立大量物件。找到原因後,修改程式和演算法。
我以前寫一個使用K-Means文字聚類演算法對幾萬條文字記錄(每條記錄的特徵向量大約10來個)進行文字聚類時,由於程式細節上有問題,就導致了Javaheap space的記憶體溢位問題,後來通過修改程式得到了解決。
2. 增加Java虛擬機器中Xms(初始堆大小)和Xmx(最大堆大小)引數的大小。如:set JAVA_OPTS= -Xms256m-Xmx1024m

第三種OutOfMemoryError:unable to create new nativethread
這種錯誤在Java執行緒個數很多的情況下容易發生,我暫時還沒遇到過,發生原意和解決辦法可以參考:http://hi.baidu.com/hexiong/blog/item/16dc9e518fb10c2542a75b3c.html