Java內(nèi)存泄露的理解與解決
來源:易賢網(wǎng) 閱讀:584 次 日期:2015-04-10 15:01:35
溫馨提示:易賢網(wǎng)小編為您整理了“Java內(nèi)存泄露的理解與解決”,方便廣大網(wǎng)友查閱!

Java內(nèi)存管理機(jī)制

在C++ 語言中,如果需要?jiǎng)討B(tài)分配一塊內(nèi)存,程序員需要負(fù)責(zé)這塊內(nèi)存的整個(gè)生命周期。從申請分配、到使用、再到最后的釋放。這樣的過程非常靈活,但是卻十分繁瑣,程序員很容易由于疏忽而忘記釋放內(nèi)存,從而導(dǎo)致內(nèi)存的泄露。 Java 語言對內(nèi)存管理做了自己的優(yōu)化,這就是垃圾回收機(jī)制。 Java 的幾乎所有內(nèi)存對象都是在堆內(nèi)存上分配(基本數(shù)據(jù)類型除外),然后由 GC ( garbage collection)負(fù)責(zé)自動(dòng)回收不再使用的內(nèi)存。

上面是Java 內(nèi)存管理機(jī)制的基本情況。但是如果僅僅理解到這里,我們在實(shí)際的項(xiàng)目開發(fā)中仍然會(huì)遇到內(nèi)存泄漏的問題。也許有人表示懷疑,既然 Java 的垃圾回收機(jī)制能夠自動(dòng)的回收內(nèi)存,怎么還會(huì)出現(xiàn)內(nèi)存泄漏的情況呢?這個(gè)問題,我們需要知道 GC 在什么時(shí)候回收內(nèi)存對象,什么樣的內(nèi)存對象會(huì)被 GC 認(rèn)為是“不再使用”的。

Java中對內(nèi)存對象的訪問,使用的是引用的方式。在 Java 代碼中我們維護(hù)一個(gè)內(nèi)存對象的引用變量,通過這個(gè)引用變量的值,我們可以訪問到對應(yīng)的內(nèi)存地址中的內(nèi)存對象空間。在 Java 程序中,這個(gè)引用變量本身既可以存放堆內(nèi)存中,又可以放在代碼棧的內(nèi)存中(與基本數(shù)據(jù)類型相同)。 GC 線程會(huì)從代碼棧中的引用變量開始跟蹤,從而判定哪些內(nèi)存是正在使用的。如果 GC 線程通過這種方式,無法跟蹤到某一塊堆內(nèi)存,那么 GC 就認(rèn)為這塊內(nèi)存將不再使用了(因?yàn)榇a中已經(jīng)無法訪問這塊內(nèi)存了)。

名單

通過這種有向圖的內(nèi)存管理方式,當(dāng)一個(gè)內(nèi)存對象失去了所有的引用之后,GC 就可以將其回收。反過來說,如果這個(gè)對象還存在引用,那么它將不會(huì)被 GC 回收,哪怕是 Java 虛擬機(jī)拋出 OutOfMemoryError 。

Java內(nèi)存泄露

一般來說內(nèi)存泄漏有兩種情況。一種情況如在C/C++ 語言中的,在堆中的分配的內(nèi)存,在沒有將其釋放掉的時(shí)候,就將所有能訪問這塊內(nèi)存的方式都刪掉(如指針重新賦值);另一種情況則是在內(nèi)存對象明明已經(jīng)不需要的時(shí)候,還仍然保留著這塊內(nèi)存和它的訪問方式(引用)。第一種情況,在 Java 中已經(jīng)由于垃圾回收機(jī)制的引入,得到了很好的解決。所以, Java 中的內(nèi)存泄漏,主要指的是第二種情況。

可能光說概念太抽象了,大家可以看一下這樣的例子:

Vector v = new Vector( 10 ); for ( int i = 1 ;i < 100 ; i ++ ){ Object o = new Object(); v.add(o); o = null ; }

在這個(gè)例子中,代碼棧中存在Vector 對象的引用 v 和 Object 對象的引用 o 。在 For 循環(huán)中,我們不斷的生成新的對象,然后將其添加到 Vector 對象中,之后將 o 引用置空。問題是當(dāng) o 引用被置空后,如果發(fā)生 GC ,我們創(chuàng)建的 Object 對象是否能夠被 GC 回收呢?答案是否定的。因?yàn)椋?GC 在跟蹤代碼棧中的引用時(shí),會(huì)發(fā)現(xiàn) v 引用,而繼續(xù)往下跟蹤,就會(huì)發(fā)現(xiàn) v 引用指向的內(nèi)存空間中又存在指向 Object 對象的引用。也就是說盡管 o 引用已經(jīng)被置空,但是 Object 對象仍然存在其他的引用,是可以被訪問到的,所以 GC 無法將其釋放掉。如果在此循環(huán)之后, Object 對象對程序已經(jīng)沒有任何作用,那么我們就認(rèn)為此 Java 程序發(fā)生了內(nèi)存泄漏。

盡管對于C/C++ 中的內(nèi)存泄露情況來說, Java 內(nèi)存泄露導(dǎo)致的破壞性小,除了少數(shù)情況會(huì)出現(xiàn)程序崩潰的情況外,大多數(shù)情況下程序仍然能正常運(yùn)行。但是,在移動(dòng)設(shè)備對于內(nèi)存和 CPU都有較嚴(yán)格的限制的情況下, Java 的內(nèi)存溢出會(huì)導(dǎo)致程序效率低下、占用大量不需要的內(nèi)存等問題。這將導(dǎo)致整個(gè)機(jī)器性能變差,嚴(yán)重的也會(huì)引起拋出 OutOfMemoryError ,導(dǎo)致程序崩潰。

一般情況下內(nèi)存泄漏的避免

在不涉及復(fù)雜數(shù)據(jù)結(jié)構(gòu)的一般情況下,Java 的內(nèi)存泄露表現(xiàn)為一個(gè)內(nèi)存對象的生命周期超出了程序需要它的時(shí)間長度。我們有時(shí)也將其稱為“對象游離”。

例如:

public class FileSearch{ private byte [] content; private File mFile; public FileSearch(File file){ mFile = file; } public boolean hasString(String str){ int size = getFileSize(mFile); content = new byte [size]; loadFile(mFile, content); String s = new String(content); return s.contains(str); } }

在這段代碼中,F(xiàn)ileSearch 類中有一個(gè)函數(shù) hasString ,用來判斷文檔中是否含有指定的字符串。流程是先將mFile 加載到內(nèi)存中,然后進(jìn)行判斷。但是,這里的問題是,將 content 聲明為了實(shí)例變量,而不是本地變量。于是,在此函數(shù)返回之后,內(nèi)存中仍然存在整個(gè)文件的數(shù)據(jù)。而很明顯,這些數(shù)據(jù)我們后續(xù)是不再需要的,這就造成了內(nèi)存的無故浪費(fèi)。

要避免這種情況下的內(nèi)存泄露,要求我們以C/C++ 的內(nèi)存管理思維來管理自己分配的內(nèi)存。第一,是在聲明對象引用之前,明確內(nèi)存對象的有效作用域。在一個(gè)函數(shù)內(nèi)有效的內(nèi)存對象,應(yīng)該聲明為 local 變量,與類實(shí)例生命周期相同的要聲明為實(shí)例變量……以此類推。第二,在內(nèi)存對象不再需要時(shí),記得手動(dòng)將其引用置空。

復(fù)雜數(shù)據(jù)結(jié)構(gòu)中的內(nèi)存泄露問題

在實(shí)際的項(xiàng)目中,我們經(jīng)常用到一些較為復(fù)雜的數(shù)據(jù)結(jié)構(gòu)用于緩存程序運(yùn)行過程中需要的數(shù)據(jù)信息。有時(shí),由于數(shù)據(jù)結(jié)構(gòu)過于復(fù)雜,或者我們存在一些特殊的需求(例如,在內(nèi)存允許的情況下,盡可能多的緩存信息來提高程序的運(yùn)行速度等情況),我們很難對數(shù)據(jù)結(jié)構(gòu)中數(shù)據(jù)的生命周期作出明確的界定。這個(gè)時(shí)候,我們可以使用Java 中一種特殊的機(jī)制來達(dá)到防止內(nèi)存泄露的目的。

之前我們介紹過,Java 的 GC 機(jī)制是建立在跟蹤內(nèi)存的引用機(jī)制上的。而在此之前,我們所使用的引用都只是定義一個(gè)“ Object o; ”這樣形式的。事實(shí)上,這只是 Java 引用機(jī)制中的一種默認(rèn)情況,除此之外,還有其他的一些引用方式。通過使用這些特殊的引用機(jī)制,配合 GC 機(jī)制,就可以達(dá)到一些我們需要的效果。

更多信息請查看IT技術(shù)專欄

更多信息請查看網(wǎng)絡(luò)編程
上一篇:Java Calendar
易賢網(wǎng)手機(jī)網(wǎng)站地址:Java內(nèi)存泄露的理解與解決
由于各方面情況的不斷調(diào)整與變化,易賢網(wǎng)提供的所有考試信息和咨詢回復(fù)僅供參考,敬請考生以權(quán)威部門公布的正式信息和咨詢?yōu)闇?zhǔn)!

2025國考·省考課程試聽報(bào)名

  • 報(bào)班類型
  • 姓名
  • 手機(jī)號
  • 驗(yàn)證碼
關(guān)于我們 | 聯(lián)系我們 | 人才招聘 | 網(wǎng)站聲明 | 網(wǎng)站幫助 | 非正式的簡要咨詢 | 簡要咨詢須知 | 新媒體/短視頻平臺(tái) | 手機(jī)站點(diǎn) | 投訴建議
工業(yè)和信息化部備案號:滇ICP備2023014141號-1 云南省教育廳備案號:云教ICP備0901021 滇公網(wǎng)安備53010202001879號 人力資源服務(wù)許可證:(云)人服證字(2023)第0102001523號
云南網(wǎng)警備案專用圖標(biāo)
聯(lián)系電話:0871-65099533/13759567129 獲取招聘考試信息及咨詢關(guān)注公眾號:hfpxwx
咨詢QQ:1093837350(9:00—18:00)版權(quán)所有:易賢網(wǎng)
云南網(wǎng)警報(bào)警專用圖標(biāo)