新聞中心
Java內(nèi)存泄漏一直Java程序中最常見的問題之一,它會導(dǎo)致內(nèi)存溢出,最終導(dǎo)致程序崩潰。我們可能對內(nèi)存泄漏很熟悉,但又不是那么熟悉,真的遇到事故的時候,內(nèi)存泄漏問題排查起來卻也沒有那么容易。本篇就再次梳理一下Java內(nèi)存泄漏的那些事。

前言
使用Java編寫程序時,我們使用new關(guān)鍵字創(chuàng)建對象。而且我們還不需要專門在對象使用完成后去釋放其占用的內(nèi)存,這是因為Java有專門的垃圾回收器來負(fù)責(zé)刪除不需要的對象。只要不被使用的對象有垃圾回收器回收,那么程序會處于正常運行的狀態(tài),但是垃圾回收器無法刪除那些不被使用的對象時,我們的Java程序則可能發(fā)生了內(nèi)存泄漏。
內(nèi)存泄漏是什么
內(nèi)存泄漏指的是JVM中某些不再需要使用的對象,仍然存活于JVM中而不能及時釋放而導(dǎo)致內(nèi)存空間的浪費。Java中內(nèi)存泄漏的原因有多種,這些眾多的因素會導(dǎo)致Java程序產(chǎn)生不同類型的內(nèi)存泄漏,隨著時間的推移,內(nèi)存泄漏會使程序增加額外的內(nèi)存資源占用,從而導(dǎo)致程序性能下降。
垃圾回收器會回收長時間沒有引用的對象,但是它不會回收那些還存在引用的對象,這就是產(chǎn)生內(nèi)存泄漏的原因。
所以為了防止內(nèi)存泄漏,程序設(shè)計之初就需要考慮去釋放那些不使用的內(nèi)存空間,而開發(fā)人員也應(yīng)當(dāng)時刻考慮內(nèi)存泄漏的可能性,并增加一些測試和檢測避免內(nèi)存泄漏。
堆和棧的內(nèi)存泄漏
Java中,我們可能會遇到棧內(nèi)存泄露和堆內(nèi)存泄漏。
其中堆內(nèi)存泄漏是由于創(chuàng)建后的對象一直存在于堆中,不再需要的對象其引用一直沒有被移除。這些無用的對象會慢慢占用內(nèi)存,最后導(dǎo)致內(nèi)存溢出。
棧內(nèi)存泄漏由于方法不斷被調(diào)用,但是一直沒有退出方法。這種情況可能發(fā)生在無限循環(huán)或遞歸掉用時,最終導(dǎo)致棧內(nèi)存溢出。
內(nèi)存泄漏的原因
Java中內(nèi)存泄漏主要是因為不能正確釋放不需要的資源,長生命周期對象持有短生命周期對象的引用。
- 靜態(tài)字段
靜態(tài)字段引起的內(nèi)存泄漏比較常見,如果某個不需要的類中含有靜態(tài)字段,那么就會造成內(nèi)存泄漏。單例模式中如果持有其他的類引用就會造成內(nèi)存泄漏,靜態(tài)集合如HashMap,LinkedList等持有的一些對象沒有及時釋放等。
- Thread Local
threadlocal引用一個對象使用完成后并沒有被及時remove掉,線程一直存活的情況下(使用線程池時)就會發(fā)生內(nèi)存泄漏。
大多時候內(nèi)存泄漏都是由于開發(fā)人員的代碼錯誤導(dǎo)致的,要防止這種內(nèi)存泄漏,就需要編寫必要的代碼來配合垃圾回收器釋放資源。
避免Java內(nèi)存泄漏的一些最佳實踐
- 使用最新穩(wěn)定版本的Java
- 盡量減少使用靜態(tài)變量,使用完之后及時賦值 null,移除引用
- 明確對象的有效作用域,盡量縮小對象的作用域。局部變量回收會很快。
- 減少長生命周期對象持有短生命周期的引用
- 各種連接應(yīng)該及時關(guān)閉(數(shù)據(jù)庫連接,網(wǎng)絡(luò),IO等)
- 使用內(nèi)存泄漏檢測工具如MAT,Visual VM,jprofile 等
- 避免在代碼中使用System.gc()
- 避免使用內(nèi)部類
內(nèi)存泄漏很難定位并修復(fù),但是我們可以遵循以下幾個步驟去定位并修復(fù):
- 確定是否存在內(nèi)存泄漏,啟用詳細(xì)的GC跟蹤。
- 使用一些第三方插件進(jìn)行分析(jprofile Visual VM等)
- 檢查調(diào)用堆棧是否有未釋放的引用(分析GC狀態(tài))
- 找出對象沒有被垃圾回收的原因
- 編寫代碼手動刪除此類對象
文章標(biāo)題:我們一起聊聊Java內(nèi)存泄漏
轉(zhuǎn)載來于:http://fisionsoft.com.cn/article/dhhdeoo.html


咨詢
建站咨詢
