JVM的內存優化

關於java.lang.OutOfMemoryError:Java Heap Space

當一個Java應用程序在對大批量數據進行操作時,JVM很容易拋出java.lang.outOfMemoryError:Java Heap Space 的錯誤,即堆棧中的內存用光。

 

 

產生OutOfMemoryError的原因

JVM拋出這種錯誤的原因,一是程序代碼本身不夠嚴謹,產生大量的垃圾,甚至因對象使用完沒有立即給它的引用賦空值,導致對象在內存堆積而無法釋放(在循環語句中特別如此),這中錯誤是可以避免的;二是JVM分配的內存值相對過少,導致Java程序無法運行。

 

針對原因一,由於jvm產生的垃圾是由我們所寫的代碼產生的,質量好的代碼產生的垃圾少,相反就會產生很多垃圾。由於jvm的最大內存不能無限增大,故增大jvm的最大內存應該是在代碼已經達到很優化時才實施的,所以優化程序纔是我們最先要做的。

如何優化程序:

第一,避免死循環。仔細檢查程序,防止出現死循環,這是比較容易檢查的。

第二,可以適當手動回收垃圾,即使調用System.gc()或Runtime.gc()。

第三,應該及時釋放種資源:內存, 數據庫的各種連接。釋放資源的時候不能依賴於java的垃圾自動回收機制,最好也不要用finalize方法,因爲無用單元回收不是一個完全可以確定的過程,作爲低優先級進程,往往是系統沒有內存時才調用垃圾回收進程。

 

針對原因二,應增加JVM的內存大小。JVM運行時候佔用一定的內存,其大小是有限定的,如果程序在運行時JVM佔用的內存大於某個限度,則會產生內存益處,也就是java.lang.outofmemoryerror

 

 

 

增加JVM的內存需要設置一些參數

一般來講,設置JVM的堆棧內存會涉及到下面四個參數:

-Xmx     設置Java Heap最大值,如-Xmx128m ,默認值爲物理內存的1/4,最佳設值應該視物理內存大小及計算機內其他內存開銷而定;

-Xms     設置Java Heap初始值,-Xms64m Server端JVM最好將-Xms和-Xmx設爲相同值,開發測試機JVM可以保留默認值;

-Xmn     設置Java Heap Young區大小,-Xmn32m 不熟悉最好保留默認值;

- Xss      設置每個線程的Stack大小,-Xss16m 不熟悉最好保留默認值;

還有兩個參數是跟非堆棧內存有關的:

-XX:PermSize             設置非堆內存初始大小,如-XX:PermSize=56m,默認是物理內存的1/6

-XX:MaxPermSize       設置最大非堆內存的大小,如-XX:MaxPermSize=128m,默認是物理內存的1/4


如何設置JVM內存分配

一、當在命令提示符下啓動並使用JVM時:

java -Xms256m -Xmx512m -XX:MaxPermSize=512m

java -Xmx128m -Xms64m -Xmn32m -Xss16m Test(只對當前運行的類Test生效)

 

二、當在集成開發環境下(如eclipse/MyEclipse)啓動並使用JVM時有三種方法:

方法1: 在eclipse根目錄下打開eclipse.ini,默認內容爲(這裏設置的是運行當前開發工具的JVM內存分配):

-vmargs

-vmargs表示以下爲虛擬機設置參數,可修改其中的參數值,也可添加-Xmn,-Xss,另外,eclipse.ini內還可以設置非堆內存,如:-XX:PermSize=56m,-XX:MaxPermSize=128m。

此處設置的參數值可以通過以下配置在開發工具的狀態欄顯示:

在eclipse根目錄下創建文件options,文件內容爲:org.eclipse.ui/perf/showHeapStatus=true

修改eclipse根目錄下的eclipse.ini文件,在開頭處添加如下內容:

-debug

重新啓動eclipse,就可以看到下方狀態條多了JVM信息。

 

方法2: 打開eclipse-窗口-首選項-Java-已安裝的JRE(對在當前開發環境中運行的java程序皆生效)

編輯當前使用的JRE,在缺省VM參數中輸入:-Xmx128m -Xms64m -Xmn32m -Xss16m

 

方法3: 打開eclipse-運行-運行-Java應用程序(只對所設置的java類生效)

選定需設置內存分配的類-自變量,在VM自變量中輸入:-Xmx128m -Xms64m -Xmn32m -Xss16m

注:如果在同一開發環境中同時進行了b和c設置,則b設置生效,c設置無效,如:

開發環境的設置爲:-Xmx256m,而類Test的設置爲:-Xmx128m -Xms64m,則運行Test時生效的設置爲:

-Xmx256m -Xms64m

 

三、當在服務器環境下(如Tomcat)啓動並使用JVM時(對當前服務器環境下所以Java程序生效):

方法1: 設置環境變量

變量名:CATALINA_OPTS

變量值:-Xmx128m -Xms64m -Xmn32m -Xss16m

方法2: 打開Tomcat根目錄下的bin文件夾,編輯catalina.bat,將其中的%CATALINA_OPTS%(共有四處)替換爲:-Xmx128m -Xms64m -Xmn32m -Xss16m

 

 

查看JVM使用的內存情況

另外,在程序運行的過程中,我們也可以調用以下方法查看JVM使用的內存情況:

Runtime.getRuntime().maxMemory(); //最大可用內存,對應-Xmx

Runtime.getRuntime().freeMemory(); //當前JVM空閒內存

Runtime.getRuntime().totalMemory(); //當前JVM佔用的內存總數,其值相當於當前JVM已使用的內存及freeMemory()的總和

關於maxMemory(),freeMemory()和totalMemory():

maxMemory()爲JVM的最大可用內存,可通過-Xmx設置,默認值爲物理內存的1/4,設值不能高於計算機物理內存;

totalMemory()爲當前JVM佔用的內存總數,其值相當於當前JVM已使用的內存及freeMemory()的總和,會隨着JVM使用內存的增加而增加;

freeMemory()爲當前JVM空閒內存,因 爲JVM只有在需要內存時才佔用物理內存使用,所以freeMemory()的值一般情況下都很小,而JVM實際可用內存並不等於 freeMemory(),而應該等於maxMemory()-totalMemory()+freeMemory()。及其設置JVM內存分配。

 

 

關於GC(垃圾回收)

在一些規模稍大的應用中,JVM的內存設置尤爲重要,想在項目中取得好的效率,GC(垃圾回收)的設置是第一步。

PermGen space:全稱是Permanent Generation space.就是說是永久保存的區域,用於存放Class和Meta信息,Class在被Load的時候被放入該區域Heap space:存放Instance。

GC(Garbage Collection)應該不會對PermGen space進行清理,所以如果你的APP會LOAD很多class的話,就很可能出現PermGen space錯誤。

 

Java Heap分爲3個區
1.Young
2.Old
3.Permanent

Young保存剛實例化的對象。當該區被填滿時,GC會將對象移到Old區。Permanent區則負責保存反射對象,本文不討論該區。

JVM的Heap分配可以使用-X參數設定:

-Xms 初始Heap大小
-Xmx    java heap最大值

-Xmn    young generation的heap大小

 

JVM有2個GC線程
第一個線程負責回收Heap的Young區
第二個線程在Heap不足時,遍歷Heap,將Young 區升級爲Older區

Older區的大小等於-Xmx減去-Xmn,不能將-Xms的值設的過大,因爲第二個線程被迫運行會降低JVM的性能。
爲什麼一些程序頻繁發生GC?

有如下原因:
1.程序內調用了System.gc()或Runtime.gc()。
2.一些中間件軟件調用自己的GC方法,此時需要設置參數禁止這些GC。
3.Java的Heap太小,一般默認的Heap值都很小。
4.頻繁實例化對象,Release對象 此時儘量保存並重用對象,例如使用StringBuffer()和String()。

如果你發現每次GC後,Heap的剩餘空間會是總空間的50%,這表示你的Heap處於健康狀態,許多Server端的Java程序每次GC後最好能有65%的剩餘空間

 

JVM調優的經驗之談:

1.Server端JVM最好將-Xms和-Xmx設爲相同值。爲了優化GC,最好讓-Xmn值約等於-Xmx的1/3。
2.一個GUI程序最好是每10到20秒間運行一次GC,每次在半秒之內完成。

注意:

1.增加Heap的大小雖然會降低GC的頻率,但也增加了每次GC的時間。並且GC運行時,所有的用戶線程將暫停,也就是GC期間,Java應用程序不做任何工作。
2.Heap大小並不決定進程的內存使用量。進程的內存使用量要大於-Xmx定義的值,因爲Java爲其他任務分配內存,例如每個線程的Stack等。

Stack的設定
每個線程都有他自己的Stack。

-Xss
每個線程的Stack大小

Stack的大小限制着線程的數量。如果Stack過大就好導致內存溢漏。-Xss參數決定Stack大小,例如-Xss1024K。如果Stack太小,也會導致Stack溢漏。

 

硬件環境

硬件環境也影響GC的效率,例如機器的種類,內存,swap空間,和CPU的數量。
如果你的程序需要頻繁創建很多transient對象,會導致JVM頻繁GC。這種情況你可以增加機器的內存,來減少Swap空間的使用。

 

4種GC

1、第一種爲單線程GC,也是默認的GC,該GC適用於單CPU機器。
2、第二種爲Throughput GC,是多線程的GC,適用於多CPU,使用大量線程的程序。第二種GC與第一種GC相似,不同在於GC在收集Young區是多線程的,但在Old區和第一種一樣,仍然採用單線程。-XX:+UseParallelGC參數啓動該GC。
3、第三種爲Concurrent Low Pause GC,類似於第一種,適用於多CPU,並要求縮短因GC造成程序停滯的時間。這種GC可以在Old區的回收同時,運行應用程序。-XX:+UseConcMarkSweepGC參數啓動該GC。
4、第四種爲Incremental Low Pause GC,適用於要求縮短因GC造成程序停滯的時間。這種GC可以在Young區回收的同時,回收一部分Old區對象。-Xincgc參數啓動該GC。

 

 

設置服務器 JVM內存

Tomcat啓動JVM內存設置:

一、Linux

在/usr/local/apache-tomcat-5.5.23/bin目錄下的catalina.sh添加:JAVA_OPTS='-Xms512m -Xmx1024m'要加“m”說明是MB,否則就是KB了,在啓動tomcat時會報內存不足。
-Xms:初始值
-Xmx:最大值
-Xmn:最小值

二、Windows

在 catalina.bat最前面加入set JAVA_OPTS=-Xms128m -Xmx350m。如果用startup.bat啓動tomcat,OK設置生效,能夠成功的分配200M內存。但是如果不是執行startup.bat 啓動tomcat而是利用windows的系統服務啓動tomcat服務,上面的設置就不生效了,就是說set JAVA_OPTS=-Xms128m -Xmx350m沒起作用,上面分配200M內存就OutOfMemory了。windows服務執行的是bin/tomcat.exe.他讀取註冊表中 的值,而不是 catalina.bat的設置。

解決辦法:

修改註冊表HKEY_LOCAL_MACHINE/SOFTWARE/Apache Software Foundation/Tomcat Service Manager/Tomcat5/Parameters/JavaOptions

原值爲

-Dcatalina.home="C:/ApacheGroup/Tomcat 5.0"
-Djava.endorsed.dirs="C:/ApacheGroup/Tomcat 5.0/common/endorsed"
-Xrs加入 -Xms300m -Xmx350m

重起tomcat服務,設置生效。

 

WebLogic啓動JVM 內存設置

在weblogic中,可以在startweblogic.cmd中對每個domain虛擬內存的大小進行設置,默認的設置是在commEnv.cmd裏面。

JBoss啓動JVM 內存設置

默認可以使用的內存爲64MB
$JBOSSDIR$/bin/run.config
JAVA_OPTS = "-server -Xms128 -Xmx512"

 

Eclipse啓動JVM 內存設置

在所在目錄下,鍵入
eclipse.exe -vmargs -Xms256m -Xmx512m
256m表示JVM堆內存最小值
512m表示JVM堆內存最大值

 

Websphere啓動JVM 內存設置

進入控制檯去設置:應用程序服務器 > server1 > 進程定義 > Java 虛擬機



參考資料:

http://blog.csdn.net/cool_rain_man/archive/2010/10/12/5935426.aspx

http://www.verybc.com/a/hulianwang/2009/1124/8839.html

http://cache.baidu.com/c?m=9d78d513d99b12eb0bfa940f5051913b4d0bd73c61979b423f94ce0887231b1f483ca5fd65351177ced82c395cfa5e5c9df33273200357e6c697950b87e0d77f74df78672b42914710d019abd6167b9c758d1baffc5fbcebed3191a9d2d7dd5f53c851007983f08e510612c96ef01634fe&p=b47e8316d9c533ec08e292755355&user=baidu

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章