內存溢出(OOM)
內存溢出是引發程序崩潰的罪魁禍首之一,當應用程序內存增長速度非常快,造成的垃圾速度已經跟不上內存消耗的速度,容易出現內存溢出問題,大多數情況下,GC會進行各種年齡段的垃圾回收,實在不行了就觸發Full GC,這時候會回收大量的內存,供程序繼續使用
javadoc對OutOfMemoryError的解釋是:沒有空閒內存,並且垃圾回收器也無法提供更多內存
沒有空閒內存一般有兩種情況:
- Java虛擬機的堆內存設置不夠
- 代碼中創建了大量大對象,並且長時間不能被垃圾收集器收集(存在被引用),比如jdk8之前的永久代,jvm對永久代很少進行垃圾回收,容易出現
OutOfMemoryError
注意:在拋出OOM異常之前,通常垃圾收集器會被觸發,儘可能去清理出空間,比如在引用機制中涉及到JVM去嘗試回軟引用
用指向的對象,也會有垃圾收集器不會被觸發的情況:比如在分配一個超大對象,jvm可以判斷出垃圾收集不能解決這個問題,所以直接拋出OOM異常
內存泄漏(Memory Leak)
內存泄漏也叫存儲滲漏,嚴格來說,只有對象不會被程序用到了,但GC又不能回收的情況,才叫內存泄漏
對比示例圖,舉兩個java中內存泄漏的案例:
- 單例模式,單例對象的生命週期是和程序一樣長的,比如lang包下的
Runtime
類,代表運行時數據環境,每個進程獨有一份,如果這個對象引用到一個生命週期很短的對象,並且這個指針沒有被及時斷掉,GC無法回收,就會導致內存泄漏 - 一些提供
close
方法的資源類,未及時調用這些方法導致內存泄漏,比如數據庫鏈接,io,網絡鏈接等,必須手動close
在日常代碼中,本可設置爲局部變量的變量被聲明爲成員或類變量導致對象生命週期邊變長甚至導致OOM,也可以叫做寬泛意義上的內存泄漏,內存泄漏不一定導致OOM,