陸立松
克拉瑪依職業(yè)技術(shù)學(xué)院,新疆 克拉瑪依 833600
JAVA中的內(nèi)存泄漏是指存在一些被分配的對(duì)象,它們有兩個(gè)特點(diǎn):其一,這些對(duì)象在有向圖中可以與存在通路相連,即可達(dá)性;其二,程序在后續(xù)不會(huì)再使用這些對(duì)象,即無(wú)用性。假如被分配的對(duì)象同時(shí)滿足這兩個(gè)條件,即可判定其為JAVA中的內(nèi)存泄漏,GC不會(huì)將其進(jìn)行回收,因此它們占用內(nèi)存。
最常見(jiàn)的是引用廢棄聚集,當(dāng)對(duì)象加入一個(gè)聚集時(shí)就不再被需要,但是未沒(méi)有被移除,特別是此聚集用St atic聲明,并存在于程序的整個(gè)生命周期時(shí),該問(wèn)題尤其突出;此外還有一種由于引用臨時(shí)對(duì)象而產(chǎn)生的錯(cuò)誤,臨時(shí)對(duì)象經(jīng)過(guò)使用就會(huì)變成垃圾,如果仍保持引用,GC就無(wú)法回收這些失效對(duì)象,從而產(chǎn)生內(nèi)存泄漏。要解決這類問(wèn)題,可以采用以下幾種方法:如果引用了失效對(duì)象要及時(shí)清除;盡可能少用靜態(tài)集合和臨時(shí)對(duì)象;對(duì)象如果不用盡量設(shè)置為Null等。
幾乎所有的大型應(yīng)用程序都會(huì)有不同形式的全局?jǐn)?shù)據(jù)庫(kù),而在FAVA中全局變量無(wú)法在所有類這之外進(jìn)行定義,其全局變量只可以利用在一個(gè)類中對(duì)靜態(tài)、公用的變量進(jìn)行定義的方法來(lái)實(shí)現(xiàn),而靜態(tài)變量會(huì)永駐內(nèi)存,因此導(dǎo)致內(nèi)存泄漏的問(wèn)題在所難免??梢岳们宄鳂I(yè)解決該問(wèn)題,這個(gè)作業(yè)為周期運(yùn)行,可以驗(yàn)證數(shù)據(jù)中的數(shù)據(jù),將無(wú)用的數(shù)據(jù)清除。此外還可以通過(guò)引用記數(shù)的方法來(lái)解決,集合的主要對(duì)集合中每個(gè)元素的引用者數(shù)量進(jìn)行統(tǒng)計(jì),引用者將不再引用元素的通知發(fā)送給集合;假如引用者數(shù)量為零,集合中的該元素就可以進(jìn)行移除。
通常系統(tǒng)處于正常運(yùn)行的情況下,其內(nèi)存占用量通常是穩(wěn)定的,而不應(yīng)出現(xiàn)無(wú)限增長(zhǎng)的問(wèn)題;與此對(duì)應(yīng)的,任何一個(gè)類的對(duì)象使用個(gè)數(shù)也同樣有一個(gè)上限,也不能無(wú)限增長(zhǎng)。按照這種假設(shè)可以對(duì)系統(tǒng)在運(yùn)行過(guò)程序所使用的內(nèi)存大小及實(shí)例個(gè)數(shù)進(jìn)行持續(xù)觀察:假如內(nèi)存大小不斷增長(zhǎng),或者特定類的實(shí)例對(duì)象數(shù)量隨著時(shí)間不斷增長(zhǎng),那么該系統(tǒng)就有存在內(nèi)存泄漏的可能。還有一種方法可以判斷是否出現(xiàn)內(nèi)存泄漏:如果應(yīng)用程序中出現(xiàn)Out Of Memory Error,系統(tǒng)也有發(fā)生內(nèi)存泄漏的可能,當(dāng)然不能排除應(yīng)用程序正在使用的內(nèi)存量確實(shí)是這么多,但是多數(shù)情況下出現(xiàn)Out Of Memory Error均有可能出現(xiàn)了內(nèi)存泄漏。此外,還可以對(duì)GC的活動(dòng)進(jìn)行持續(xù)的監(jiān)控,如果隨著時(shí)間的增加系統(tǒng)內(nèi)存使用量也不斷上升,那就有發(fā)生內(nèi)存泄漏的可能。
當(dāng)檢測(cè)到確實(shí)出現(xiàn)了內(nèi)存泄漏,進(jìn)行處理時(shí)就要利用專業(yè)工具,這些工具采用字節(jié)碼技術(shù)及JVMTI等方法由JVM獲取內(nèi)存系統(tǒng)信息。其中JVMTI為標(biāo)準(zhǔn)接口,其前身是JVMPI,其作為外部工具與JVM通信,搜集JVM的信息;而字節(jié)碼儀器所引用的是預(yù)處理技術(shù),該技術(shù)利用探針獲取工具所需要的字節(jié)信息。不過(guò)目前多數(shù)處理內(nèi)存泄漏的工具均是基于JVMTI進(jìn)行的,JVMTI會(huì)使系統(tǒng)的內(nèi)存增加,執(zhí)行程序的速度變慢。而另外一種工具JRockit Memory Leak Detector是基于BEAJVM運(yùn)行的,它內(nèi)嵌于BEAJ Rockit JVM,系統(tǒng)全速運(yùn)行時(shí)也可以使用,而且不會(huì)出現(xiàn)其它與此類工具相關(guān)聯(lián)的性能開(kāi)銷,所以不存在上述缺點(diǎn)。應(yīng)用JRockit Memory Leak Detector處理內(nèi)存泄漏可以經(jīng)由以下幾個(gè)步驟來(lái)實(shí)現(xiàn):
首先借助趨勢(shì)分析找出存在泄漏的對(duì)象類,JRockit Memory Leak Detector所提供的趨勢(shì)分析功能可以描述應(yīng)用程序中各類使用堆空間的情形,可以通過(guò)它了解某一類型實(shí)例所占用空間的大小,或者占用了堆的哪一部分,存在實(shí)例的數(shù)量和堆空間使用的每秒增加速度,其中增長(zhǎng)過(guò)快的對(duì)象就值得懷疑。其次,尋找與泄漏對(duì)象相關(guān)的其它類,通過(guò)對(duì)趨勢(shì)分析表的分析選擇一個(gè)可疑類型,所有具有指向選中類型的實(shí)例的類型均可以在一個(gè)圖中顯示出來(lái),用戶就能夠回溯到造成引用的根本原因。類的實(shí)例能夠被顯示、內(nèi)觀,指向一個(gè)選中實(shí)例的所有實(shí)例均能夠顯示于一張實(shí)例圖,可以通過(guò)分配跟蹤對(duì)某個(gè)類的分配情況進(jìn)行跟蹤。最后再向下發(fā)掘,找出獨(dú)立的對(duì)象間互相聯(lián)系的方式。此外,該工具還可以動(dòng)態(tài)的尋找所有內(nèi)存分配的堆棧路徑,同時(shí)通過(guò)上述3種特性,可以把該工具集成在JVM中,從而對(duì)內(nèi)存泄漏進(jìn)行安全有效的捕捉與修復(fù)。
在實(shí)際應(yīng)用過(guò)程中,如果可以結(jié)合GC的運(yùn)行機(jī)制,在進(jìn)行設(shè)計(jì)與編碼時(shí)更具針對(duì)性,從而有效的減少或者消除內(nèi)存泄漏。具體的措施如下:第一,盡量少用靜態(tài)對(duì)象變量或者靜態(tài)集合類,因?yàn)楸混o態(tài)集合類引用的對(duì)象無(wú)法被GC回收,易導(dǎo)致內(nèi)存泄漏;第二,使用內(nèi)部類要謹(jǐn)慎,因?yàn)閮?nèi)部類中往往隱藏有外部類對(duì)象實(shí)例的引用,如果未得到釋放會(huì)造成整個(gè)系列對(duì)象無(wú)法釋放;第三,不可采用生命周期長(zhǎng)的對(duì)象去管理生命周期短的對(duì)象;第四,物理連接要及時(shí)關(guān)閉;第五,釋放資源或者清除引用時(shí)要調(diào)用對(duì)象的特定方法;第六,清除本地的系統(tǒng)資源時(shí)可以采用Finalize方法。
[1]馮濤,宋成明.清剿Java程序中的內(nèi)存泄漏[J].計(jì)算機(jī)技術(shù)與發(fā)展,2008(4).
[2]賈曉霞,吳際,金茂忠,等.Java程序內(nèi)存泄漏綜述[J].計(jì)算機(jī)應(yīng)用研究,2009(6).
[3]黃山,楊全勝,杜中軍,等.Java內(nèi)存管理和內(nèi)存泄漏的研究[J].中國(guó)民航飛行學(xué)院學(xué)報(bào),2009(5).
[4]陳華.探討JAVA的內(nèi)存泄漏問(wèn)題[J].IT技術(shù)論壇,2008(33).