java-内存溢出与内存泄漏
目錄
內存溢出(OOM)
內存泄漏(Memory?Leak)
內存溢出(OOM)
1.內存溢出相對于內存泄漏來說,盡管更容易被理解,但是同樣的,內存溢出也是引發程序崩潰的罪魁禍首之一。
2.由于GC一直在發展,所有一般情況下,除非應用程序占用的內存增長速度非常快,造成垃圾回收已經跟不上內存消耗的速度,否則不太容易出現OOM的情況。
3.大多數情況下,GC會進行各種年齡段的垃圾回收,實在不行了就放大招,來一次獨占式的Full?GC操作,這時候會回收大量的內存,供應用程序繼續使用。
4.javadoc中對OutOfMemoryError的解釋是,沒有空閑內存,并且垃圾收集器也無法提供更多內存。
5.首先說沒有空閑內存的情況:說明Java虛擬機的堆內存不夠。原因有二:
(1)Java虛擬機的堆內存設置不夠。
? ? 比如:可能存在內存泄漏問題;也很有可能就是堆的大小不合理,比如我們要處理比較可觀的數據量,但是沒有顯式指定JVM堆大小或者指定數值偏小。我們可以通過參數-Xms、-Xmx來調整。
(2)代碼中創建了大量大對象,并且長時間不能被垃圾收集器收集(存在被引用)
? ? 對于老版本的Oracle?JDK,因為永久代的大小時有限的,并且JVM對永久代垃圾回收(如,常量池回收、卸載不再需要的類型)非常不積極,所以當我們不斷添加新類型的時候,永久代出現OutOfMemoryError也非常多見,尤其是在運行時存在大量動態類型生成的場合;類似intern字符串緩存占用太多空間,也會導致OOM問題。對應的異常信息,會標記出來和永久代相關:“java.lang.OutOfMemoryError:PermGen?space”。
? ? 隨著元數據區的引入,方法區內存已經不再那么窘迫,所以相應的OOM有所改觀,出現OOM,異常信息則變成了:“java.lang.OutOfMemoryError:Metaspace”。直接內存不足,也會導致OOM。
6.這里面隱含著一層意思是,在拋出OutOfMemoryError之前,通常垃圾收集器會被觸發,盡其所能去清理出空間。
? ? 例如:在引用機制分析中,涉及到JVM會去嘗試回收軟引用指向的對象等。
? ? 在java.nio.BIts.reserveMemory()方法中,我們能清除的看到,System.gc()會被調用,以清理空間。
7.當然,也不是在任何情況下垃圾收集器都會被觸發的。
? ? 比如,我們去分配一個超大對象,類似一個超大數組超過堆的最大值,JVM可以判斷出垃圾收集并不能解決這個問題,所以直接拋出OutOfMemoryError。
內存泄漏(Memory?Leak)
1.也稱作“存儲滲漏”。嚴格來說,只有對象不會再被程序用到了,但是GC又不能回收他們的情況,才叫內存泄漏。
2.但實際情況很多時候一些不太好的實踐(或疏忽)會導致對象的生命周期變得很長甚至導致OOM,也可以叫做寬泛意義上的“內存泄漏”。
3.盡管內存泄漏并不會立刻引起程序崩潰,但是一旦發生內存泄漏,程序中的可用內存就會被逐步蠶食,直至耗盡所有內存,最終出現OutOfMemory異常,導致程序崩潰。
4.注意,這里的存儲空間并不是指物理內存,而是指虛擬機內存大小,這個虛擬內存大小取決于磁盤交換區設定的大小。
舉例:
1.單例模式
? ? 單例的生命周期和應用程序時一樣長的,所以單例程序中,如果持有對外部對象的引用的話,那么這個外部對象是不能被回收的,則會導致內存泄漏的發生。
2.一些提供close的資源未關閉導致內存泄漏
? ? 數據庫連接(dataSource.getConnection()),網絡連接(socket)和io連接必須手動close,否則是不能被回收的。
?
總結
以上是生活随笔為你收集整理的java-内存溢出与内存泄漏的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java的System.gc()的理解
- 下一篇: 认识java-STW:Stop the