会不会导致内存泄漏_Java内存泄漏!为什么会泄漏?如何泄漏?怎么定位?
JVM應該可以算Java中最為核心的部分了,其中開箱即用的內存管理又是JVM中的核心組成部分。我們都知道JVM的內存管理具有垃圾回收功能(Java Garbage Collector),編碼時只需要new而無需主動的釋放(類似于C++中的delete操作),所以Java中比較少出現內存泄露的情況。比較少出現,并不一定就不會出現,那么Java程序在什么時候會出現內存泄露呢?出現內存泄露該如何排查呢?
Java程序為什么會有內存泄露
什么是內存泄露呢?內存泄露可以定義為:當一個對象已經不再被應用程序使用以后,它所占用的內存沒有得到及時的釋放,導致內存使用量隨著時間的推移不斷的增加,最終導致應用程序崩潰的現象(Java中會在new新對象的時候拋出OutOfMemoryError)。
對于Java程序而言,當一個Object已經不會被程序所使用,但是它還被其它對象所引用,從而導致GC的時候無法被回收,從而導致內存泄露。
下圖比較直觀的展示了Java內存泄露發生的情形:
從上圖我們可以把對象分為兩大類:被引用的和不被引用的。垃圾回收的時候不釋放那些不被引用的對象,被引用的對象則不會被釋放,即便是這些對象后續一直都沒有被用過。
定位Java內存泄露是比較麻煩的事情,需要使用到JVM提供的多種工具來進行內存分析,并且往往還需要結合代碼進行分析。
Java堆內存泄露
首先我們來看看Java程序中最為常見的堆內存泄露。
如果想要直觀的模擬出堆內存泄露,我們需要設置一一個較小的堆大小(內存泄露是獨立存在的,和對內存大小無關,不過較小的堆內存大小可以更直觀的觀察到內存泄露)。
我們可以通過如下兩個啟動參數設置對內存大小:
通過靜態變量來演示內存泄露
首先我們通過如下的代碼來看看看看正常Java代碼運行時的內存變化情況:
啟動參數:-Xms20m -Xmx20m
運行是的內存變化圖:
在我們的代碼中我們每秒調用一次test方法,這個方法中會往list中添加數據,但是在方法返回之后這些數據就處于無引用狀態了(并不一定會立馬進行GC),我們每10秒調用一次System.gc()(full GC)。從內存監控圖上能夠直觀的觀察到堆內存的使用變化曲線。
接下來我們對上面的代碼做一下修改:
靜態變量保存了過多不在使用的對象引用導致的內存泄露是我們編碼過程中最為常見的一種內存泄露方式。下面的代碼就演示了這個情況:
為了更加直觀的觀察內存變化,我稍微調整了一下每次插入的數據個數,啟動參數仍舊和上面一下。這個時候我們能夠得到如下圖所示的內存變化曲線:
從曲線中我們可以發現,堆內存使用量一直在增加,并沒有和前一個示例一樣在full GC后釋放沒有使用的堆內存,每次調用test方法后添加到list中的對象都會被list所引用,所以GC是不會收集并釋放這些內存的。
如何定位和解決內存泄漏
Java的內存泄漏定位一般是比較困難的,需要使用到很多的實踐經驗和調試技巧。下面是一些比較通用的方法:
總結
以上是生活随笔為你收集整理的会不会导致内存泄漏_Java内存泄漏!为什么会泄漏?如何泄漏?怎么定位?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于python的保留字_Python中
- 下一篇: java美元兑换,(Java实现) 美元