內存溢出雖然很棘手,但也有相應的解決辦法,能夠按照從易到難,一步步的解決。
第一步,就是修改JVM啓動參數,直接增長內存。這一點看上去彷佛很簡單,但很容易被忽略。JVM默承認以使用的內存爲64M,Tomcat默承認以使用的內存爲128MB,對於稍複雜一點的系統就會不夠用。在某項目中,就由於啓動參數使用的默認值,常常報"OutOfMemory"錯誤。所以,-Xms,-Xmx參數必定不要忘記加。
第二步,檢查錯誤日誌,查看"OutOfMemory"錯誤前是否有其它異常或錯誤。在一個項目中,使用兩個數據庫鏈接,其中專用於發送短信的數據庫鏈接使用DBCP鏈接池管理,用戶爲不將短信發出,有意將數據庫鏈接用戶名改錯,使得日誌中有許多數據庫鏈接異常的日誌,一段時間後,就出現"OutOfMemory"錯誤。經分析,這是因爲DBCP鏈接池BUG引發的,數據庫鏈接不上後,沒有將鏈接釋放,最終使得DBCP報"OutOfMemory"錯誤。通過修改正確數據庫鏈接參數後,就沒有再出現內存溢出的錯誤。
查看日誌對於分析內存溢出是很是重要的,經過仔細查看日誌,分析內存溢出前作過哪些操做,能夠大體定位有問題的模塊。
第三步,安排有經驗的編程人員對代碼進行走查和分析,找出可能發生內存溢出的位置。重點排查如下幾點:
檢查代碼中是否有死循環或遞歸調用。
檢查是否有大循環重複產生新對象實體。
檢查對數據庫查詢中,是否有一次得到所有數據的查詢。通常來講,若是一次取十萬條記錄到內存,就可能引發內存溢出。這個問題比較隱蔽,在上線前,數據庫中數據較少,不容易出問題,上線後,數據庫中數據多了,一次查詢就有可能引發內存溢出。所以對於數據庫查詢儘可能採用分頁的方式查詢。
檢查List、MAP等集合對象是否有使用完後,未清除的問題。List、MAP等集合對象會始終存有對對象的引用,使得這些對象不能被GC回收。
第四步,使用內存查看工具動態查看內存使用狀況。某個項目上線後,每次系統啓動兩天後,就會出現內存溢出的錯誤。這種狀況通常是代碼中出現了緩慢的內存泄漏,用上面三個步驟解決不了,這就須要使用內存查看工具了。
內存查看工具備許多,比較有名的有:Optimizeit Profiler、JProbeProfiler、JinSight和Java1.5的Jconsole等。它們的基本工做原理大同小異,都是監測Java程序運行時全部對象的申請、釋放等動做,將內存管理的全部信息進行統計、分析、可視化。開發人員能夠根據這些信息判斷程序是否有內存泄漏問題。通常來講,一個正常的系統在其啓動完成後其內存的佔用量是基本穩定的,而不該該是無限制的增加的。持續地觀察系統運行時使用的內存的大小,能夠看到在內存使用監控窗口中是基本規則的鋸齒形的圖線,若是內存的大小持續地增加,則說明系統存在內存泄漏問題。經過間隔一段時間取一次內存快照,而後對內存快照中對象的使用與引用等信息進行比對與分析,能夠找出是哪一個類的對象在泄漏。
經過以上四個步驟的分析與處理,基本能處理內存溢出的問題。固然,在這些過程當中也須要至關的經驗與敏感度,須要在實際的開發與調試過程當中不斷積累。
內存溢出(out of memory),通俗理解就是內存不夠,一般在運行大型軟件或遊戲時,軟件或遊戲所須要的內存遠遠超出了你主機內安裝的內存所承受大小,就叫內存溢出。此時軟件或遊戲就運行不了,系統會提示內存溢出,有時候會自動關閉軟件,重啓電腦或者軟件後釋放掉一部份內存又能夠正常運行該軟件或遊戲一段時間。
內存溢出已是軟件開發歷史上存在了近40年的"老大難"問題,像在"紅色代碼"病毒事件中表現的那樣,它已經成爲黑客攻擊企業網絡的"罪魁禍首"。 如在一個域中輸入的數據超過了它的要求就會引起數據溢出問題,多餘的數據就能夠做爲指令在計算機上運行。據有關安全小組稱,操做系統中超過50%的安全漏洞都是由內存溢出引發的,其中大多數與微軟的技術有關。
定義及緣由
內存溢出是指應用系統中存在沒法回收的內存或使用的內存過多,最終使得程序運行要用到的內存大於虛擬機能提供的最大內存。爲了解決Java中內存溢出問題,咱們首先必須瞭解Java是如何管理內存的。Java的內存管理就是對象的分配和釋放問題。在Java中,內存的分配是由程序完成的,而內存的釋放是由垃圾收集器(GarbageCollection,GC)完成的,程序員不須要經過調用GC函數來釋放內存,由於不一樣的JVM實現者可能使用不一樣的算法管理GC,有的是內存使用到達必定程度時,GC纔開始工做,也有定時執行的,有的是中斷式執行GC。但GC只能回收無用而且再也不被其它對象引用的那些對象所佔用的空間。Java的內存垃圾回收機制是從程序的主要運行對象開始檢查引用鏈,當遍歷一遍後發現沒有被引用的孤立對象就做爲垃圾回收。 引發內存溢出的緣由有不少種,常見的有如下幾種: 內存中加載的數據量過於龐大,如一次從數據庫取出過多數據; 集合類中有對對象的引用,使用完後未清空,使得JVM不能回收; 代碼中存在死循環或循環產生過多重複的對象實體; 使用的第三方軟件中的BUG; 啓動參數內存值設定的太小。