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