相信有一定java開發經驗的人或多或少都會遇到outofmemoryerror的問題,這個問題曾困擾了我很長時間,随着解決各類問題經驗的積累以及對問題根源的探索,終于有了一個比較深入的認識。
在解決java記憶體溢出問題之前,需要對jvm(java虛拟機)的記憶體管理有一定的認識。jvm管理的記憶體大緻包括三種不同類型的記憶體區域:permanent
generation space(永久儲存區域)、heap space(堆區域)、java
stacks(java棧)。其中永久儲存區域主要存放class(類)和meta的資訊,class第一次被load的時候被放入permgen
space區域,class需要存儲的内容主要包括方法和靜态屬性。堆區域用來存放class的執行個體(即對象),對象需要存儲的内容主要是非靜态屬性。每
次用new建立一個對象執行個體後,對象執行個體存儲在堆區域中,這部分空間也被jvm的垃圾回收機制管理。而java棧跟大多數程式設計語言包括彙編語言的棧功能相
似,主要基本類型變量以及方法的輸入輸出參數。java程式的每個線程中都有一個獨立的堆棧。容易發生記憶體溢出問題的記憶體空間包括:permanent
generation space和heap space。
第一種outofmemoryerror: permgen
space
發生這種問題的原意是程式中使用了大量的jar或class,使java虛拟機裝載類的空間不夠,與permanent
generation 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虛拟機建立的對象太多,在進行垃圾回收之間,虛拟機配置設定的到堆記憶體空間已經用滿了,與heap
space有關。解決這類問題有兩種思路:
1. 檢查程式,看是否有死循環或不必要地重複建立大量對象。找到原因後,修改程式和算法。
我以前寫一個使用k-means文本聚類算法對幾萬條文本記錄(每條記錄的特征向量大約10來個)進行文本聚類時,由于程式細節上有問題,就導緻了java
heap space的記憶體溢出問題,後來通過修改程式得到了解決。
2. 增加java虛拟機中xms(初始堆大小)和xmx(最大堆大小)參數的大小。如:set java_opts= -xms256m
-xmx1024m
第三種outofmemoryerror:unable to create new native
thread