內存溢出原理:
我們知道,Java程序本身是不能直接在計算機上運行的,它需要依賴於硬件基礎之上的操作系統和JVM(Java虛擬機)。
Java程序啟動時JVM都會分配一個初始內存和最大內存給這個應用程序。這個初始內存和最大內存在一定程度上會影響應用程序的性能。
JVM其實就是操作系統上的一個普通程序(進程名叫java,這個程序可以解釋執行class文件,系統中當前運行了多少個java程序就會有多少個java進程)。
當Java進程啟動時會首先分配一塊堆內存(最小內存),以后每當java程序要求JVM(java進程)分配內存時,JVM就會在預先分配的那塊內存上為java程序分配內存,當預先分配的那塊內存用完時,JVM會再向操作系統要內存(物理內存),但是JVM不會無限制的向操作系統要內存,當它占用的實際內存達到一個預定值(最大可用內存)時,如果Java程序還向JVM要內存,並且JVM無法通過垃圾回收機制回收當前堆中的內存來為java程序服務時,它就會給程序拋出異常:java.lang.OutOfMemoryError。
其中內存回收時機並不是在用掉內存達到最大可用內存時才進行,它的運行時機是不確定的。可見JVM的最大可用內存就是java程序能夠使用的最大內存。
例如:
我們把某JAVA程序的JVM最大可用內存設為200M,而我們的物理內存是1G。
這種情況下,我們的java程序最多能使用200M內存,雖然我們可能還有800M的內存可用,但是當我們的程序用掉200M后,如果再要內存,JVM不會因為我們還有800M的內存而為我們分配內存,它會拋出java.lang.OutOfMemoryError異常。
Runtime.getRuntime().totalMemory() :返回 Java 虛擬機中的內存總量。
Runtime.getRuntime().maxMemory() :返回 Java 虛擬機試圖使用的最大內存量。
Runtime.getRuntime().freeMemory() :返回 Java 虛擬機中的空閑內存量。
單位是字節(Byte)
1024Byte(字節)=1KB
1024KB=1MB
1024MB=1GB
1024GB=1TB
Tomcat服務器的例子:
1.java.lang.OutOfMemoryError: PermGen space
PermGen space的全稱是Permanent Generation space,是指內存的永久保存區域OutOfMemoryError: PermGen space。從文字上看就是內存溢出,解決方法是加大內存。為什么會內存溢出,這是由於這塊內存主要是被JVM存放Class和Meta信息的,Class在被Load的時候被放入PermGen space區域,它和存放Instance的Heap區域不同,GC(Garbage Collection)不會在主程序運行期對PermGen space進行清理,所以如果你的APP會LOAD很多CLASS的話,就很可能出現PermGen space錯誤。這種錯誤常見在web服務器對JSP進行pre compile的時候。如果你的WEB APP下都用了大量的第三方jar, 其大小超過了jvm默認的大小(4M)那么就會產生此錯誤信息了。
解決方法: 手動設置MaxPermSize大小
修改TOMCAT_HOME/bin/catalina.sh
在“echo "Using CATALINA_BASE: $CATALINA_BASE"”上面加入以下行:
JAVA_OPTS="-server -XX:PermSize=64M -XX:MaxPermSize=128m
建議:將相同的第三方jar文件移置到tomcat/shared/lib目錄下,這樣可以達到減少jar 文檔重復占用內存的目的。
2.java.lang.OutOfMemoryError: Java heap space
JVM堆的設置是指java程序運行過程中JVM可以調配使用的內存空間的設置。JVM在啟動的時候會自動設置Heap size的值,其初始空間(即-Xms)是物理內存的1/64,最大空間(-Xmx)是物理內存的1/4。可以利用JVM提供的-Xmn -Xms -Xmx等選項可進行設置。Heap size 的大小是Young Generation 和Tenured Generaion 之和。在JVM中如果98%的時間是用於GC且可用的Heap size 不足2%的時候將拋出此異常信息。
解決方法:手動設置Heap size
修改TOMCAT_HOME/bin/catalina.sh
在“echo "Using CATALINA_BASE: $CATALINA_BASE”“上面加入以下行:
JAVA_OPTS="-server -Xms800m -Xmx800m -XX:MaxNewSize=256m"
提示:Heap Size 最大不要超過可用物理內存的80%,一般的要將-Xms和-Xmx選項設置為相同,而-Xmn為1/4的-Xmx值。
Tomcat默認可以使用的內存為128MB,在較大型的應用項目中,這點內存是不夠的,需要調大。有以下幾種方法可以選用:
第一種方法:
Windows下,在文件/bin/catalina.bat,Unix下,在文件/bin/catalina.sh的前面,增加如下設置:
JAVA_OPTS='-Xms【初始化內存大小】 -Xmx【可以使用的最大內存】'
需要把這個兩個參數值調大。例如:
JAVA_OPTS='-Xms256m -Xmx512m'
表示初始化內存為256MB,可以使用的最大內存為512MB。
第二種方法:
環境變量中設 變量名:JAVA_OPTS 變量值:-Xms512m -Xmx512m
第三種方法:
前兩種方法針對的是bin目錄下有catalina.bat的情況(比如直接解壓的Tomcat等),但是有些安裝版的Tomcat下沒有catalina.bat,這個時候可以采用如下方法,當然這個方法也是最通用的方法:打開tomcatHome/\bin/\tomcat5w.exe,點擊Java選項卡,然后將會發現其中有這么兩項:Initial memory pool和Maximum memory pool.Initial memory pool這個就是初始化設置的內存的大小。Maximum memory pool這個是最大內存的大小 設置完了就按確定然后再重啟TOMCAT你就會發現tomcat中jvm可用的內存改變了
另外需要考慮的是Java提供的垃圾回收機制。虛擬機的堆大小決定了虛擬機花費在收集垃圾上的時間和頻度。收集垃圾可以接受的速度與應用有關,應該通過分析實際的垃圾收集的時間和頻率來調整。如果堆的大小很大,那么完全垃圾收集就會很慢,但是頻度會降低。如果你把堆的大小和內存的需要一致,完全收集就很快,但是會更加頻繁。調整堆大小的的目的是最小化垃圾收集的時間,以在特定的時間內最大化處理客戶的請求。在基准測試的時候,為保證最好的性能,要把堆的大小設大,保證垃圾收集不在整個基准測試的過程中出現。
如果系統花費很多的時間收集垃圾,請減小堆大小。一次完全的垃圾收集應該不超過 3-5 秒。如果垃圾收集成為瓶頸,那么需要指定代的大小,檢查垃圾收集的詳細輸出,研究 垃圾收集參數對性能的影響。一般說來,你應該使用物理內存的 80% 作為堆大小。當增加處理器時,記得增加內存,因為分配可以並行進行,而垃圾收集不是並行的。
一個要注意的地方:建議把內存的最高值跟最低值的差值縮小,不然會浪費很多內存的, 最低值加大 ,最高值可以隨便設,但是要根據實際的物理內存 ,如果內存設置太大了,比如設置了512M最大內存,但如果沒有512M可用內存,Tomcat就不能啟動,還有可能存在內存被系統回收,終止進程的情況。