有關Java內存溢出及內存消耗的小知識


內存溢出原理: 
我們知道,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就不能啟動,還有可能存在內存被系統回收,終止進程的情況。 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM