內存溢出是一個很是隱式的問題,通過相關資料的查詢,先總結一下內存溢出的關鍵字:what(溢出表現)、origin(內存分配及回收)、where(溢出類型)、why(泄露緣由)、how(預防及解決方案)。
1、what(溢出表現)
1. 服務器內存長期不合理佔用,內存常常處於高位佔用,很難回收到低位;
2. 服務器極爲不穩定,幾乎每兩天從新啓動一次,有時甚至天天從新啓動一次;
3. 服務器常常作 Full GC(Garbage Collection),並且時間很長,大約須要 30-40秒,應用服務器在作 Full GC的時候是不響應客戶的交易請求的,很是影響系統性能。
4. 服務器的內存佔用不是鋸齒形波動,而是趨勢向上,最後宕機。
2、origin(起源)
1. 內存溢出是指沒法回收的內存積攢過多或者正在使用的內存過多,最終致使程序運行須要的內存大於虛擬機所能提供的最大內存,從而致使內存溢出。
所以,爲了解決這個問題,從抽絲剝繭的角度來看,首先第一步須要明白起源,即明白內存分配以及回收的方式:
「在Java中,內存的分配是由程序完成的,而內存的釋放是由垃圾收集器(Garbage Collection,GC)完成的,程序員不須要經過調用GC函數來釋放內存,由於不一樣的JVM實現者可能使用不一樣的算法管理GC,有的是內存使用到達必定程度時,GC纔開始工做,也有定時執行的,有的是中斷式執行GC。但GC只能回收無用而且再也不被其它對象引用的那些對象所佔用的空間。Java的內存垃圾回收機制是從程序的主要運行對象開始檢查引用鏈,當遍歷一遍後發現沒有被引用的孤立對象就做爲垃圾回收。」 --引用
我以爲這一段話說的比較準確,總結起來就是:1.內存的分配及回收基本均可以交由程序靜默進行,釋放不了的核心在於引用還在。
2. 那麼何時進行垃圾回收(分爲Scavenge GC 跟 Full GC)呢?
2.1 Scavenge GC 主要集中在 Eden 園區,通常狀況下,當新對象生成,而且在Eden申請空間失敗時,就會觸發Scavenge GC,對Eden區域進行GC,清除非存活對象,而且把尚且存活的對象移動到Survivor區。而後整理Survivor的兩個區。這種方式的GC是對年輕代的Eden區進行,不會影響到年老代。
2.2 Full GC。速度很慢,對整個堆進行整理,包括Young、Tenured和Perm。引發 Full GC 的方式有:老年代被寫滿,持久代被寫滿以及System.gc()被顯示調用。
3、where(主要溢出類型)
下一步咱們繼續關注主要在什麼位置有可能內存溢出:
1. java.lang.OutOfMemoryError: Java heap space (堆溢出)
堆是垃圾回收關注的重點,若是在垃圾回收之間 Java 虛擬機建立了過多的對象,虛擬機分配到堆內存的空間已經滿了,那麼就會報這個錯誤。
2. Java.lang.OutOfMemoryError: PermGen space (永久區溢出)
若是說堆是給咱們程序員使用的話,那麼非堆就是給JVM本身使用的,非堆主要存在類的基本信息,他與堆的不一樣之處在於非堆中在運行期間GC不會釋放空間。按照該異常的原義,指的是程序中使用了大量的jar或class,使java虛擬機裝載類的空間不夠(注意這時候是MaxPermSize較小)。
4、why(泄漏緣由)
根據時間順序,咱們大體能夠總結以下:
1. 啓動參數內存值設定的太小,沒法加載過大的包;
2. 內存中加載的數據量過於龐大,如一次從數據庫取出過多數據;
3. 集合類中有對對象的引用,使用完後未清空,使得JVM不能回收;
4. 代碼中存在死循環或循環產生過多重複的對象實體;
5. 使用的第三方軟件中的BUG;
6. 注意其餘不健壯的代碼緣由;
6.1 注意無引用對象的及時釋放;
6.2 沒法避免的大量字符串處理,儘可能使用 StringBuffer 而非 String,緣由是每個 String 都須要佔用一塊內存空間;
6.3 注意靜態變量的使用,由於靜態變量是全局變量,不會被回收;
6.4 注意大對象的建立及使用,注意顯示聲明極大的數組對象;
6.5 注意循環體體內的對象建立;
6.6 注意是否一次性查詢出來大量的數據;
6.7 檢查List及Map是否有對象的引用一直存在;
5、how(解決方案及預防方案)
通常來講,系統穩定以後,內存的使用是保持在必定水平的,若是發現內存的使用隨時間的增加而呈現線性的增加,那麼就有可能說明正在內存泄露。
通常處理的思路,跟以上緣由其實一一對應:
1. 增大JVM的啓動內存,-Xms256m -Xmx256m -XX:MaxNewSize=256m -XX:MaxPermSize=256m;
2. 檢查錯誤日誌;
3. 代碼層面的檢查(參見第四大點的緣由);
4. 使用檢查工具,Optimizeit Profiler、JProbe Profiler等等。這些工具的主要點都會聚焦在追蹤對象的申請、釋放等動做,將內存管理的全部信息進行統計而後可視化,根據這些信息,能夠追蹤到上述三個步驟仍然沒法檢查到的泄露對象。
文章參考: