首先了解一下JVM內存管理的機制。
1)堆(Heap)和非堆(Non-heap)內存
按照官方的說法:“Java 虛擬機具有一個堆,堆是運行時數據區域,所有類實例和數組的內存均從此處分配。堆是在 Java 虛擬機啓動時創建的。”“在JVM中堆之外的內存稱爲非堆內存(Non-heap memory)”。
可以看出JVM主要管理兩種類型的內存:堆和非堆。簡單來說堆就是Java代碼可及的內存,是留給開發人員使用的;非堆就是JVM留給自己用的,
所以方法區、JVM內部處理或優化所需的內存(如JIT編譯後的代碼緩存)、每個類結構(如運行時常數池、字段和方法數據)以及方法和構造方法的代碼都在非堆內存中。
堆內存分配
JVM初始分配的堆內存由-Xms指定,默認是物理內存的1/64;JVM最大分配的堆內存由-Xmx指定,默認是物理內存的1/4。默認空餘堆內存小於40%時,JVM就會增大堆直到-Xmx的最大限制;
空餘堆內存大於70%時,JVM會減少堆直到-Xms的最小限制。因此服務器一般設置-Xms、-Xmx 相等以避免在每次GC 後調整堆的大小。
說明:如果-Xmx 不指定或者指定偏小,應用可能會導致java.lang.OutOfMemory錯誤,此錯誤來自JVM,不是Throwable的,無法用try...catch捕捉。
非堆內存分配
JVM使用-XX:PermSize設置非堆內存初始值,默認是物理內存的1/64;由XX:MaxPermSize設置最大非堆內存的大小,默認是物理內存的1/4。(還有一說:MaxPermSize缺省值和-server -client選項相關,
-server選項下默認MaxPermSize爲64m,-client選項下默認MaxPermSize爲32m。這個我沒有實驗。)
上面錯誤信息中的PermGen space的全稱是Permanent Generation space,是指內存的永久保存區域。還沒有弄明白PermGen space是屬於非堆內存,還是就是非堆內存,但至少是屬於了。
XX:MaxPermSize設置過小會導致java.lang.OutOfMemoryError: PermGen space 就是內存益出。
說說爲什麼會內存益出:
(1)這一部分內存用於存放Class和Meta的信息,Class在被 Load的時候被放入PermGen space區域,它和存放Instance的Heap區域不同。
(2)GC(Garbage Collection)不會在主程序運行期對PermGen space進行清理,所以如果你的APP會LOAD很多CLASS 的話,就很可能出現PermGen space錯誤。
這種錯誤常見在web服務器對JSP進行pre compile的時候。
2)JVM內存限制(最大值)
首先JVM內存限制於實際的最大物理內存,假設物理內存無限大的話,JVM內存的最大值跟操作系統有很大的關係。簡單的說就32位處理器雖然可控內存空間有4GB,但是具體的操作系統會給一個限制,
這個限制一般是2GB-3GB(一般來說Windows系統下爲1.5G-2G,Linux系統下爲2G-3G),而64bit以上的處理器就不會有限制了。
2. 爲什麼有的機器我將-Xmx和-XX:MaxPermSize都設置爲512M之後Eclipse可以啓動,而有些機器無法啓動?
通過上面對JVM內存管理的介紹我們已經瞭解到JVM內存包含兩種:堆內存和非堆內存,另外JVM最大內存首先取決於實際的物理內存和操作系統。所以說設置VM參數導致程序無法啓動主要有以下幾種原因:
1) 參數中-Xms的值大於-Xmx,或者-XX:PermSize的值大於-XX:MaxPermSize;
2) -Xmx的值和-XX:MaxPermSize的總和超過了JVM內存的最大限制,比如當前操作系統最大內存限制,或者實際的物理內存等等。說到實際物理內存這裏需要說明一點的是,
如果你的內存是1024MB,但實際系統中用到的並不可能是1024MB,因爲有一部分被硬件佔用了。
內存溢出解決辦法
Tomcat的啓動分爲startup.bat啓動和註冊爲windows服務的啓動,下面一一說明。
1.startup.bat啓動
在tomcat_home/bin目錄下找到catalina.bat,用文本編輯器打開,加上下面一行:
set JAVA_OPTS= -Xms1024M -Xmx1024M -XX:PermSize=256M -XX:MaxNewSize=256M -XX:MaxPermSize=256M
解釋一下各個參數:
-Xms1024M:初始化堆內存大小(注意,不加M的話單位是KB)
-Xmx1029M:最大堆內存大小
-XX:PermSize=256M:初始化類加載內存池大小
-XX:MaxPermSize=256M:最大類加載內存池大小
-XX:MaxNewSize=256M:這個還不清楚哈,有知道的說聲
還有一個-server參數,是指啓動jvm時以服務器方式啓動,比客戶端啓動慢,但性能較好,大家可以自己選擇。
2.windows服務啓動
如果你的tomcat是註冊爲windows服務並且是以服務方式啓動的,那麼上面的方法就無效了,因爲這時tomcat啓動是讀取註冊表的參數,而不是讀取批處理文件的參數,這時我們有兩種方法來設置jvm參數。
第一種比較簡單,tomcat爲我們提供了一個設置啓動參數的窗體,雙擊tomcat_home/bin目錄下的tomcat6w.exe,如圖
下方的Initial memory pool就是初始化堆內存大小,Maximun memory pool是最大堆內存大小。
而要設置Perm Gen池的大小就要在Java Option裏面加參數了,在裏面加上:
-Dcatalina.base=%tomcat_home%
-Dcatalina.home=%tomcat_home%
-Djava.endorsed.dirs=%tomcat_home%\endorsed
-Djava.io.tmpdir=%tomcat_home%\temp
-XX:PermSize=256M
-XX:MaxPermSize=256M
-XX:ReservedCodeCacheSize=48M
-Duser.timezone=GMT+08
(PS:網上說每一行後面不要有空格,沒試過)
第二種方法是打開註冊表->HKEY_LOCAL_MACHINE\SOFTWARE\Apache Software Foundation\Procrun 2.0\Tomcat6\Parameters\Java(路徑可能有一點點差別)
修改Options的值,把剛纔上面那些參數加進去就OK了。(別忘了先備份一下註冊表)