tomcat伺服器運作一段時間後,tomcat控制台報錯:
java.lang.outOfMemoryError,java.lang.outOfMemoryError
然後tomcat服務立即死,隻有重新開機tomcat才能恢複服務
初步确定原因
1,java虛拟機jvm記憶體過小
2,程式不嚴密,産生太多的垃圾
解決對策:
針對原因1:
增加jvm的記憶體大小。
JVM即是java虛拟機,它運作時候占用一定的記憶體,其大小是有限定的,如果程式在運作時jvm占用的記憶體大于某個限度,則會産生記憶體益處,也就是“java.lang.outofmemoryerror”。
作為web容器的tomcat(包括resin等)在運作時候,會直接或間接産生一個java.exe程序,可以看成一個jvm程序。由于這些web容器在不停的運作,也就是jvm不停的工作,jvm會不斷的産生垃圾(所胃的垃圾,簡單可認為是指程式進行後遺留下的無用的對象),也會不停的回收垃圾。當回收垃圾的速度比産生垃圾的速度的慢時,垃圾就會不停的增長,當垃圾增長超過一定限度,也就是垃圾對象占用的記憶體超過jvm記憶體的最大限度。此時jvm就會出現運作時錯誤,也就是error,由于error屬于緻命錯誤,不能處理,故tomcat等就會斷掉,隻有重新開機tomcat。
針對此,我們可以設想,如果jvm記憶體的沒有限度,并且有無限大的記憶體,那jvm就永遠不會出現記憶體溢出了。但是,傻子都知道我們在做白日夢。既然這樣行不通,那我們就退一步,所胃退一步海闊天空嘛,我們可以适當增大jvm的最大記憶體,以緩解jvm來不及回收垃圾而導緻的記憶體不斷增長。jdk1.4預設jvm的最大記憶體為128M,我們可以把tomcat等web容器的jvm最大記憶體加大,比如我們可以增大到256M,甚至1G等,隻要不超過計算的記憶體都行,不過凡事都有個度,設定過大肯定不是最好的。至于要個jvm設定多大的記憶體則要通過我們不斷嘗試。
如何增加jvm的記憶體呢?
第一,在執行某個class檔案時候,可以使用java -Xmx256M aa.class來設定運作aa.class時jvm所允許占用的最大記憶體為256M。
第二,對tomcat容器,可以在啟動時對jvm設定記憶體限度。對tomcat,可以在catalina.bat中添加:
"set CATALINA_OPTS=-Xms128M -Xmx256M
set JAVA_OPTS=-Xms128M -Xmx256M",或者把%CATALINA_OPTS%和%JAVA_OPTS%代替為-Xms128M -Xmx256M,其具體操作可以到網上去找找。
第三,對resin容器,同樣可以在啟動時對jvm設定記憶體限度。在bin檔案夾下建立一個startup.bat檔案,内容如下:
@echo off
call "httpd.exe" "-Xms128M" "-Xmx256M"
:end
其中"-Xms128M"為最小記憶體,"-Xmx256M"為最大記憶體。
第四,其他容器,如ibm webswhere,可以通過配置檔案加大jvm記憶體。
第五,修改jdk核心,個人想法,但沒去研究過。
針對原因2:
由于jvm産生的垃圾是由我們所寫的代碼産生的,品質好的代碼産生的垃圾少,相反就會産生很多垃圾。由于jvm的最大記憶體不能無限增大,故增大jvm的最大記憶體應該是在代碼已經達到很優化時才實施的,是以優化程式才是我們最先要做的。
如何優化程式:
第一,避免死循環。仔細檢查程式,防止出現死循環,這是比較容易檢查的。
第二,可以适當手動回收垃圾
第三,
應該及時釋放種資源:記憶體, 資料庫的各種連接配接。
釋放資源的時候不能依賴于java的垃圾自動回收機制,最好也不要用finalize方法,因為無用單元回收不是一個完全可以确定的過程,作為低優先級程序,往往是系統沒有記憶體時才調用垃圾回收程序。
由于我們在Java程式中聲明了好多對象,占用了記憶體空間,程式結束時沒有将這些對象或對象的引用進行釋放,進而導緻Java虛拟機(JVM)進行垃圾回收(GC)時,不能夠回收這些對象。這樣,Java所用的記憶體就會一直增加,直至溢出,進而導緻Resin當機。
導緻Java記憶體溢出的根本原因是Java程式的不規範或不健壯。是以,從根本上解決Java記憶體溢出的唯一方法就是修改Java程式,及時地釋放沒用的對象,釋放記憶體空間。
除了這個方法以外,還有一些應急措施,可以臨時緩解一下系統的運作。Resin預設情況是當機以後不能通路網站,必須手動重新開機Resin,但不可能一直看在機器旁邊,看Resin有沒有當機。是以這裡介紹一種讓Resin自重新開機的方法。
打開Resin的配置檔案resin.conf(一般情況下,該檔案在Resin目錄的conf檔案夾下)。裡面有一段内容如下所示:
這段内容預設情況下是被注釋的。它的功能是讓Resin每隔一分鐘就測試一下能否通路/ping/ping.jsp檔案,測試時間是1s,如果不成功,就重試三次。如果三次都不成功,Resin就自動重新開機。是以将這段話下半部分(從"")的注釋去掉,然後在Resin的釋出目錄中建立一個檔案夾ping,在ping檔案夾下建立一個ping.jsp檔案,檔案中可以寫入簡單的一句話,如:。
好,大功告成,啟動Resin,這樣就不用擔心Java記憶體溢出導緻Resin當機了,因為Resin當機後會馬上重新啟動。