




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
JAVAJAVA垃圾回收機(jī)制與內(nèi)存泄露問題#1.垃圾收集算法的核心思想Java語言建立了垃圾收集機(jī)制,用以跟蹤正在使用的對(duì)象和發(fā)現(xiàn)并回收不再使用(引用)的對(duì)象。該機(jī)制可以有效防范動(dòng)態(tài)內(nèi)存分配中可能發(fā)生的兩個(gè)危險(xiǎn):因內(nèi)存垃圾過多而引發(fā)的內(nèi)存耗盡,以及不恰當(dāng)?shù)膬?nèi)存釋放所造成的內(nèi)存非法引用。垃圾收集算法的核心思想是:對(duì)虛擬機(jī)可用內(nèi)存空間,即堆空間中的對(duì)象進(jìn)行識(shí)別,如果對(duì)象正在被引用那么稱其為存活對(duì)象,反之,如果對(duì)象不再被引用,則為垃圾對(duì)象,可以回收其占據(jù)的空間,用于再分配。垃圾收集算法的選擇和垃圾收集系統(tǒng)參數(shù)的合理調(diào)節(jié)直接影響著系統(tǒng)性能,因此需要開發(fā)人員做比較深入的了解。2.觸發(fā)主GC(GarbageCollector)的條件JVM進(jìn)行次GC的頻率很高,但因?yàn)檫@種GC占用時(shí)間極短,所以對(duì)系統(tǒng)產(chǎn)生的影響不大。更值得關(guān)注的是主GC的觸發(fā)條件,因?yàn)樗鼘?duì)系統(tǒng)影響很明顯??偟膩碚f,有兩個(gè)條件會(huì)觸發(fā)主GC:當(dāng)應(yīng)用程序空閑時(shí),即沒有應(yīng)用線程在運(yùn)行時(shí),GC會(huì)被調(diào)用。因?yàn)镚C在優(yōu)先級(jí)最低的線程中進(jìn)行,所以當(dāng)應(yīng)用忙時(shí),GC線程就不會(huì)被調(diào)用,但以下條件除外。Java堆內(nèi)存不足時(shí),GC會(huì)被調(diào)用。當(dāng)應(yīng)用線程在運(yùn)行,并在運(yùn)行過程中創(chuàng)建新對(duì)象,若這時(shí)內(nèi)存空間不足,JVM就會(huì)強(qiáng)制地調(diào)用GC線程,以便回收內(nèi)存用于新的分配。若GC一次之后仍不能滿足內(nèi)存分配的要求,JVM會(huì)再進(jìn)行兩次GC作進(jìn)一步的嘗試,若仍無法滿足要求,則JVM將報(bào)“outofmemory"的錯(cuò)誤,Java應(yīng)用將停止。由于是否進(jìn)行主GC由JVM根據(jù)系統(tǒng)環(huán)境決定,而系統(tǒng)環(huán)境在不斷的變化當(dāng)中,所以主GC的運(yùn)行具有不確定性,無法預(yù)計(jì)它何時(shí)必然出現(xiàn),但可以確定的是對(duì)一個(gè)長期運(yùn)行的應(yīng)用來說,其主GC是反復(fù)進(jìn)行的。3?減少GC開銷的措施根據(jù)上述GC的機(jī)制,程序的運(yùn)行會(huì)直接影響系統(tǒng)環(huán)境的變化,從而影響GC的觸發(fā)。若不針對(duì)GC的特點(diǎn)進(jìn)行設(shè)計(jì)和編碼,就會(huì)出現(xiàn)內(nèi)存駐留等一系列負(fù)面影響。為了避免這些影響,基本的原則就是盡可能地減少垃圾和減少GC過程中的開銷。具體措施包括以下幾個(gè)方面:不要顯式調(diào)用System.gc()此函數(shù)建議JVM進(jìn)行主GC,雖然只是建議而非一定,但很多情況下它會(huì)觸發(fā)主GC,從而增加主GC的頻率,也即增加了間歇性停頓的次數(shù)。盡量減少臨時(shí)對(duì)象的使用臨時(shí)對(duì)象在跳出函數(shù)調(diào)用后,會(huì)成為垃圾,少用臨時(shí)變量就相當(dāng)于減少了垃圾的產(chǎn)生,從而延長了出現(xiàn)上述第二個(gè)觸發(fā)條件出現(xiàn)的時(shí)間,減少了主GC的機(jī)會(huì)。對(duì)象不用時(shí)最好顯式置為Null一般而言,為Null的對(duì)象都會(huì)被作為垃圾處理,所以將不用的對(duì)象顯式地設(shè)為Null,有利于GC收集器判定垃圾,從而提高了GC的效率。盡量使用StringBuffer而不用String來累加字符串(詳見blog另一篇文章JAVA中String與StringBuffer)由于String是固定長的字符串對(duì)象,累加String對(duì)象時(shí),并非在一個(gè)String對(duì)象中擴(kuò)增,而是重新創(chuàng)建新的String對(duì)象,如Str5=Strl+Str2+Str3+Str4,這條語句執(zhí)行過程中會(huì)產(chǎn)生多個(gè)垃圾對(duì)象,因?yàn)閷?duì)次作“+”操作時(shí)都必須創(chuàng)建新的String對(duì)象,但這些過渡對(duì)象對(duì)系統(tǒng)來說是沒有實(shí)際意義的,只會(huì)增加更多的垃圾。避免這種情況可以改用StringBuffer來累加字符串,因StringBuffer是可變長的,它在原有基礎(chǔ)上進(jìn)行擴(kuò)增,不會(huì)產(chǎn)生中間對(duì)象。⑸能用基本類型如Int,Long,就不用Integer,Long對(duì)象基本類型變量占用的內(nèi)存資源比相應(yīng)對(duì)象占用的少得多,如果沒有必要,最好使用基本變量。(6)盡量少用靜態(tài)對(duì)象變量靜態(tài)變量屬于全局變量,不會(huì)被GC回收,它們會(huì)一直占用內(nèi)存。(7)分散對(duì)象創(chuàng)建或刪除的時(shí)間集中在短時(shí)間內(nèi)大量創(chuàng)建新對(duì)象,特別是大對(duì)象,會(huì)導(dǎo)致突然需要大量內(nèi)存JVM在面臨這種情況時(shí),只能進(jìn)行主GC,以回收內(nèi)存或整合內(nèi)存碎片,從而增加主GC的頻率。集中刪除對(duì)象,道理也是一樣的。它使得突然出現(xiàn)了大量的垃圾對(duì)象,空閑空間必然減少,從而大大增加了下一次創(chuàng)建新對(duì)象時(shí)強(qiáng)制主GC的機(jī)會(huì)。4.gc與finalize方法(l)gc方法請(qǐng)求垃圾回收使用System.gc()可以不管JVM使用的是哪一種垃圾回收的算法,都可以請(qǐng)求Java的垃圾回收。需要注意的是,調(diào)用System.gc(也僅僅是一個(gè)請(qǐng)求。JVM接受這個(gè)消息后,并不是立即做垃圾回收,而只是對(duì)幾個(gè)垃圾回收算法做了加權(quán),使垃圾回收操作容易發(fā)生,或提早發(fā)生,或回收較多而已。⑵finalize方法透視垃圾收集器的運(yùn)行在JVM垃圾收集器收集一個(gè)對(duì)象之前,一般要求程序調(diào)用適當(dāng)?shù)姆椒ㄡ尫刨Y源,但在沒有明確釋放資源的情況下,Java提供了缺省機(jī)制來終止化該對(duì)象釋放資源,這個(gè)方法就是finalize()。它的原型為:protectedvoidfinalize()throwsThrowable在finalize。方法返回之后,對(duì)象消失,垃圾收集開始執(zhí)行。原型中的throwsThrowable表示它可以拋出任何類型的異常。因此,當(dāng)對(duì)象即將被銷毀時(shí),有時(shí)需要做一些善后工作??梢园堰@些操作寫在finalize()方法里。protectedvoidfinalize(){//finalizationcodehere}⑶代碼示例classGarbage{intindex;staticintcount;Garbage(){count++;System.out.println("object"+count+"construct");setID(count);}voidsetID(intid){index=id;}protectedvoidfinalize()//重寫finalize方法{System.out.println("object"+index+"isreclaimed");}publicstaticvoidmain(String[]args){newGarbage();newGarbage();newGarbage();newGarbage();System.gc();//請(qǐng)求運(yùn)行垃圾收集器}}5.Java內(nèi)存泄漏由于采用了垃圾回收機(jī)制,任何不可達(dá)對(duì)象(對(duì)象不再被引用)都可以由垃圾收集線程回收。因此通常說的Java內(nèi)存泄漏其實(shí)是指無意識(shí)的、非故意的對(duì)象引用,或者無意識(shí)的對(duì)象保持。無意識(shí)的對(duì)象引用是指代碼的開發(fā)人員本來已經(jīng)對(duì)對(duì)象使用完畢,卻因?yàn)榫幋a的錯(cuò)誤而意外地保存了對(duì)該對(duì)象的引用(這個(gè)引用的存在并不是編碼人員的主觀意愿),從而使得該對(duì)象一直無法被垃圾回收器回收掉,這種本來以為可以釋放掉的卻最終未能被釋放的空間可以認(rèn)為是被“泄漏了”??紤]下面的程序,在ObjStack類中,使用push和pop方法來管理堆棧中的對(duì)象。兩個(gè)方法中的索引(index)用于指示堆棧中下一個(gè)可用位置。push方法存儲(chǔ)對(duì)新對(duì)象的引用并增加索引值,而pop方法減小索引值并返回堆棧最上面的元素。在main方法中,創(chuàng)建了容量為64的棧,并64次調(diào)用push方法向它添加對(duì)象,此時(shí)index的值為64,隨后又32次調(diào)用pop方法,則index的值變?yōu)?2,出棧意味著在堆棧中的空間應(yīng)該被收集。但事實(shí)上,pop方法只是減小了索引值,堆棧仍然保持著對(duì)那些對(duì)象的引用。故32個(gè)無用對(duì)象不會(huì)被GC回收,造成了內(nèi)存滲漏。publicclassObjStack{privateObject[]stack;privateintindex;ObjStack(intindexcount){stack=newObject[indexcount];index=0;}publicvoidpush(Objectobj){stack[index]=obj;index++;}publicObjectpop(){index--;returnstack[index];}}publicclassPushpop{publicstaticvoidmain(String[]args){inti=0;Objecttempobj;ObjStackstack1=newObjStack(64);//new—個(gè)ObjStack對(duì)象,并調(diào)用有參構(gòu)造函數(shù)。分配stackObj數(shù)組的空間大小為64,可以存64個(gè)對(duì)象,從0開始存儲(chǔ)。while(i<64){tempobj=newObject。;〃循環(huán)newObj對(duì)象,把每次循環(huán)的對(duì)象一一存放在stackObj數(shù)組中。stack1.push(tempobj);i++;System.out.println(”第"+i+"次進(jìn)棧"+"\t");}while(i>32){tempobj=stackl.pop();〃這里造成了空間的浪費(fèi)。//正確的pop方法可改成如下所指示,當(dāng)引用被返回后,堆棧刪除對(duì)他們的引用,因此垃圾收集器在以后可以回收他們。/**publicObjectpop(){index--;Objecttemp=stack[index];stack[index]=null;returntemp;}*/i--;System.out.println(”第"+(64-i)+"次出棧"+"\t");}}}如何消除內(nèi)存泄漏雖然Java虛擬機(jī)(JVM)及其垃圾收集器(garbagecollector,GC)負(fù)責(zé)管理大多數(shù)的內(nèi)存任務(wù),Java軟件程序中還是有可能出現(xiàn)內(nèi)存泄漏。實(shí)際上,這在大型項(xiàng)目中是一個(gè)常見的問題。避免內(nèi)存泄漏的第一步是要弄清楚它是如何發(fā)生的。本文介紹了編寫Java代碼的一些常見的內(nèi)存泄漏陷阱,以及編寫不泄漏代碼的一些最佳實(shí)踐。一旦發(fā)生了內(nèi)存泄漏,要指出造成泄漏的代碼是非常困難的。因此本文還介紹了一種新工具,用來診斷泄漏并指出根本原因。該工具的開銷非常小,因此可以使用它來尋找處于生產(chǎn)中的系統(tǒng)的內(nèi)存泄漏。垃圾收集器的作用雖然垃圾收集器處理了大多數(shù)內(nèi)存管理問題,從而使編程人員的生活變得更輕松了,但是編程人員還是可能犯錯(cuò)而導(dǎo)致出現(xiàn)內(nèi)存問題。簡單地說,GC循環(huán)地跟蹤所有來自“根”對(duì)象(堆棧對(duì)象、靜態(tài)對(duì)象、JNI句柄指向的對(duì)象,諸如此類)的引用,并將所有它所能到達(dá)的對(duì)象標(biāo)記為活動(dòng)的。程序只可以操縱這些對(duì)象;其他的對(duì)象都被刪除了。因?yàn)镚C使程序不可能到達(dá)已被刪除的對(duì)象,這么做就是安全的。雖然內(nèi)存管理可以說是自動(dòng)化的,但是這并不能使編程人員免受思考內(nèi)存管理問題之苦。例如,分配(以及釋放)內(nèi)存總會(huì)有開銷,雖然這種開銷對(duì)編程人員來說是不可見的。創(chuàng)建了太多對(duì)象的程序?qū)?huì)比完成同樣的功能而創(chuàng)建的對(duì)象卻比較少的程序更慢一些(在其他條件相同的情況下)。而且,與本文更為密切相關(guān)的是,如果忘記“釋放”先前分配的內(nèi)存,就可能造成內(nèi)存泄漏。如果程序保留對(duì)永遠(yuǎn)不再使用的對(duì)象的引用,這些對(duì)象將會(huì)占用并耗盡內(nèi)存,這是因?yàn)樽詣?dòng)化的垃圾收集器無法證明這些對(duì)象將不再使用。正如我們先前所說的,如果存在一個(gè)對(duì)對(duì)象的引用,對(duì)象就被定義為活動(dòng)的,因此不能刪除。為了確保能回收對(duì)象占用的內(nèi)存,編程人員必須確保該對(duì)象不能到達(dá)。這通常是通過將對(duì)象字段設(shè)置為null或者從集合(collection)中移除對(duì)象而完成的。但是,注意,當(dāng)局部變量不再使用時(shí),沒有必要將其顯式地設(shè)置為null。對(duì)這些變量的引用將隨著方法的退出而自動(dòng)清除。概括地說,這就是內(nèi)存托管語言中的內(nèi)存泄漏產(chǎn)生的主要原因:保留下來卻永遠(yuǎn)不再使用的對(duì)象引用。典型泄漏既然我們知道了在Java中確實(shí)有可能發(fā)生內(nèi)存泄漏,就讓我們來看一些典型的內(nèi)存泄漏及其原因。全局集合在大的應(yīng)用程序中有某種全局的數(shù)據(jù)儲(chǔ)存庫是很常見的,例如一個(gè)JNDI樹或一個(gè)會(huì)話表。在這些情況下,必須注意管理儲(chǔ)存庫的大小。必須有某種機(jī)制從儲(chǔ)存庫中移除不再需要的數(shù)據(jù)。這可能有多種方法,但是最常見的一種是周期性運(yùn)行的某種清除任務(wù)。該任務(wù)將驗(yàn)證儲(chǔ)存庫中的數(shù)據(jù),并移除任何不再需要的數(shù)據(jù)。另一種管理儲(chǔ)存庫的方法是使用反向鏈接(referrer)計(jì)數(shù)。然后集合負(fù)責(zé)統(tǒng)計(jì)集合中每個(gè)入口的反向鏈接的數(shù)目。這要求反向鏈接告訴集合何時(shí)會(huì)退出入口。當(dāng)反向鏈接數(shù)目為零時(shí),該元素就可以從集合中移除了。緩存緩存是一種數(shù)據(jù)結(jié)構(gòu),用于快速查找已經(jīng)執(zhí)行的操作的結(jié)果。因此,如果一個(gè)操作執(zhí)行起來很慢,對(duì)于常用的輸入數(shù)據(jù),就可以將操作的結(jié)果緩存,并在下次調(diào)用該操作時(shí)使用緩存的數(shù)據(jù)。緩存通常都是以動(dòng)態(tài)方式實(shí)現(xiàn)的,其中新的結(jié)果是在執(zhí)行時(shí)添加到緩存中的。典型的算法是:檢查結(jié)果是否在緩存中,如果在,就返回結(jié)果。如果結(jié)果不在緩存中,就進(jìn)行計(jì)算。將計(jì)算出來的結(jié)果添加到緩存中,以便以后對(duì)該操作的調(diào)用可以使用。該算法的問題(或者說是潛在的內(nèi)存泄漏)出在最后一步。如果調(diào)用該操作時(shí)有相當(dāng)多的不同輸入,就將有相當(dāng)多的結(jié)果存儲(chǔ)在緩存中。很明顯這不是正確的方法。為了預(yù)防這種具有潛在破壞性的設(shè)計(jì),程序必須確保對(duì)于緩存所使用的內(nèi)存容量有一個(gè)上限。因此,更好的算法是:檢查結(jié)果是否在緩存中,如果在,就返回結(jié)果。如果結(jié)果不在緩存中,就進(jìn)行計(jì)算。如果緩存所占的空間過大,就移除緩存最久的結(jié)果。將計(jì)算出來的結(jié)果添加到緩存中,以便以后對(duì)該操作的調(diào)用可以使用。通過始終移除緩存最久的結(jié)果,我們實(shí)際上進(jìn)行了這樣的假設(shè):在將來,比起緩存最久的數(shù)據(jù),最近輸入的數(shù)據(jù)更有可能用到。這通常是一個(gè)不錯(cuò)的假設(shè)。新算法將確保緩存的容量處于預(yù)定義的內(nèi)存范圍之內(nèi)。確切的范圍可能很難計(jì)算,因?yàn)榫彺嬷械膶?duì)象在不斷變化,而且它們的引用包羅萬象。為緩存設(shè)置正確的大小是一項(xiàng)非常復(fù)雜的任務(wù),需要將所使用的內(nèi)存容量與檢索數(shù)據(jù)的速度加以平衡。解決這個(gè)問題的另一種方法是使用java.lang.ref.SoftReference類跟蹤緩存中的對(duì)象。這種方法保證這些引用能夠被移除,如果虛擬機(jī)的內(nèi)存用盡而需要更多堆的話。ClassLoaderJavaClassLoader結(jié)構(gòu)的使用為內(nèi)存泄漏提供了許多可乘之機(jī)。正是該結(jié)構(gòu)本身的復(fù)雜性使ClassLoader在內(nèi)存泄漏方面存在如此多的問題。ClassLoader的特別之處在于它不僅涉及“常規(guī)”的對(duì)象引用,還涉及元對(duì)象引用,比如:字段、方法和類。這意味著只要有對(duì)字段、方法、類或ClassLoader的對(duì)象的引用,ClassLoader就會(huì)駐留在JVM中。因?yàn)镃lassLoader本身可以關(guān)聯(lián)許多類及其靜態(tài)字段,所以就有許多內(nèi)存被泄漏了。確定泄漏的位置通常發(fā)生內(nèi)存泄漏的第一個(gè)跡象是:在應(yīng)用程序中出現(xiàn)了OutOfMemoryError。這通常發(fā)生在您最不愿意它發(fā)生的生產(chǎn)環(huán)境中,此時(shí)幾乎不能進(jìn)行調(diào)試。有可能是因?yàn)闇y(cè)試環(huán)境運(yùn)行應(yīng)用程序的方式與生產(chǎn)系統(tǒng)不完全相同,因而導(dǎo)致泄漏只出現(xiàn)在生產(chǎn)中。在這種情況下,需要使用一些開銷較低的工具來監(jiān)控和查找內(nèi)存泄漏。還需要能夠無需重啟系統(tǒng)或修改代碼就可以將這些工具連接到正在運(yùn)行的系統(tǒng)上。可能最重要的是,當(dāng)進(jìn)行分析時(shí),需要能夠斷開工具而保持系統(tǒng)不受干擾。雖然OutOfMemoryError通常都是內(nèi)存泄漏的信號(hào),但是也有可能應(yīng)用程序確實(shí)正在使用這么多的內(nèi)存;對(duì)于后者,或者必須增加JVM可用的堆的數(shù)量,或者對(duì)應(yīng)用程序進(jìn)行某種更改,使它使用較少的內(nèi)存。但是,在許多情況下,OutOfMemoryError都是內(nèi)存泄漏的信號(hào)。一種查明方法是不間斷地監(jiān)控GC的活動(dòng),確定內(nèi)存使用量是否隨著時(shí)間增加。如果確實(shí)如此,就可能發(fā)生了內(nèi)存泄漏。非常多人在談?wù)搩?nèi)存泄露問題,當(dāng)然對(duì)于C/C++來說,這個(gè)應(yīng)該是老掉牙的問題,不過非常多Java人員也越來越多得討論這個(gè)問題,我這里寫個(gè)小結(jié),希望對(duì)大家有一定的參考價(jià)值。內(nèi)存泄漏的慨念C/C++是程式員自己管理內(nèi)存,Java內(nèi)存是由GC自動(dòng)回收的。我雖然不是非常熟悉C++,不過這個(gè)應(yīng)該沒有犯常識(shí)性錯(cuò)誤吧。什么是內(nèi)存泄露?內(nèi)存泄露是指系統(tǒng)中存在無法回收的內(nèi)存,有時(shí)候會(huì)造成內(nèi)存不足或系統(tǒng)崩潰。在C/C++中分配了內(nèi)存不釋放的情況就是內(nèi)存泄露。Java存在內(nèi)存泄露我們必須先承認(rèn)這個(gè),才能接著討論。雖然Java存在內(nèi)存泄露,不過基本上不用非常關(guān)心他,特別是那些對(duì)代碼本身就不講究的就更不要去關(guān)心這個(gè)了。Java中的內(nèi)存泄露當(dāng)然是指:存在無用不過垃圾回收器無法回收的對(duì)象。而且即使有內(nèi)存泄露問題存在,也不一定會(huì)表現(xiàn)出來。Java中參數(shù)都是傳值的。對(duì)于基本類型,大家基本上沒有異議,不過對(duì)于引用類型我們也不能有異議。Java內(nèi)存泄露情況JVM回收算法是非常復(fù)雜的,我也不知道他們?cè)趺磳?shí)現(xiàn)的,不過我只知道他們要實(shí)現(xiàn)的就是:對(duì)于沒有被引用的對(duì)象是能回收的。所以你要造成內(nèi)存泄露就要做到:中國.網(wǎng)管聯(lián)盟持有對(duì)無用對(duì)象的引用!不要以為這個(gè)非常容易做到,既然無用,你怎么還會(huì)持有他的引用?既然你還持有他,他怎么會(huì)是無用的呢?我實(shí)在想不到比那個(gè)堆棧更經(jīng)典的例子了,以致于我還要引用別人的例子,下面的例子不是我想到的,是書上看到的,當(dāng)然如果沒有在書上看到,可能過一段時(shí)間我自己也想的到,可是那時(shí)我說是我自己想到的也沒有人相信的。publicclassStack{privateObject[]elements=newObject[10];privateintsize=0;publicvoidpush(Objecte){ensureCapacity();elements[size++]=e;}publicObjectpop(){if(size==0)thrownewEmptyStackException();returnelements[--size];}privatevoidensureCapacity(){if(elements.length==size){Object[]oldElements=elements;elements=newObject[2*elements.length+1];System.arraycopy(oldElements,0,elements,0,size);}}}上面的原理應(yīng)該非常簡單,如果堆棧加了10個(gè)元素,然后全部彈出來,雖然堆棧是空的,沒有我們要的東西,不過這是個(gè)對(duì)象是無法回收的,這個(gè)才符合了內(nèi)存泄露的兩個(gè)條件:無用,無法回收。中國網(wǎng)管聯(lián)盟不過就是存在這樣的東西也不一定會(huì)導(dǎo)致什么樣的后果,如果這個(gè)堆棧用的比較少,也就浪費(fèi)了幾個(gè)K內(nèi)存而已,反正我們的內(nèi)存都上G了,哪里會(huì)有什么影響,再說這個(gè)東西非??炀蜁?huì)被回收的,有什么關(guān)系。下面看兩個(gè)例子。例子1publicclassBad{publicstaticStacks=Stack();static{s.push(newObject());s.pop();//這里有一個(gè)對(duì)象發(fā)生內(nèi)存泄露s.push(newObject());//上面的對(duì)象能被回收了,等于是自愈了}因?yàn)槭莝tatic,就一直存在到程式退出,不過我們也能看到他有自愈功能,就是說如果你的Stack最多有100個(gè)對(duì)象,那么最多也就只有100個(gè)對(duì)象無法被回收其實(shí)這個(gè)應(yīng)該非常容易理解,Stack內(nèi)部持有100個(gè)引用,最壞的情況就是他們都是無用的,因?yàn)槲覀円坏┓判碌倪M(jìn)取,以前的引用自然消失!例子2publicclassNotTooBad{publicvoiddoSomething(){Stacks=newStack();s.push(newObject());//othercodes.pop();〃這里同樣導(dǎo)致對(duì)象無法回收,內(nèi)存泄露.}〃退出方法,s自動(dòng)無效,s能被回收,Stack內(nèi)部的引用自然沒了,所以www_bitscn_com//這里也能自愈,而且能說這個(gè)方法不存在內(nèi)存泄露問題,不過是晚一點(diǎn)〃交給GC而已,因?yàn)樗欠忾]的,對(duì)外不開放,能說上面的代碼99.9999%的//情況是不會(huì)造成所有影響的,當(dāng)然你寫這樣的代碼不會(huì)有什么壞的影響,不過//絕對(duì)能說是垃圾代碼!沒有矛盾吧,我在里面加一個(gè)空的for循環(huán)也不會(huì)有//什么太大的影響吧,你會(huì)這么做嗎?}上面兩個(gè)例子都不過是小打小鬧,不過C/C++中的內(nèi)存泄露就不是Bad了,而是Worst了。他們?nèi)绻惶帥]有回收就永遠(yuǎn)無法回收,頻繁的調(diào)用這個(gè)方法內(nèi)存不就用光了!因?yàn)镴ava更有自愈功能(我自己起的名字,還沒申請(qǐng)專利),所以Java的內(nèi)存泄露問題幾乎能忽略了,不過知道的人就不要犯了。不知者無罪!Java存在內(nèi)存泄露,不過也不要夸大其辭。如果你對(duì)Java都不是非常熟,你根本就不用關(guān)心這個(gè),我說過你無意中寫出內(nèi)存泄露的例子就像你中一千萬相同概率小,開玩笑了,其實(shí)應(yīng)該是小的多的多!而且即使你有幸寫出這樣的代碼,中獎(jiǎng)了!基本上都是一包洗衣粉,不會(huì)讓你發(fā)財(cái),對(duì)系統(tǒng)沒有什么大的影響。杞人憂天的情況無話可說型Objectobj=newObject。;obj=null;//這個(gè)完全多此一舉,因?yàn)橥顺隽俗饔梅秶瑢?duì)象的引用自動(dòng)消失中國網(wǎng)管聯(lián)盟//不要在你的程式中出現(xiàn)這樣的語句,沒有錯(cuò),不過就是不雅觀思考不對(duì)型voidfunc(Objecto){o=newObject();return}當(dāng)我們知道Java參數(shù)是傳值,就知道上面的方法什么也沒錯(cuò),就是申請(qǐng)了一個(gè)對(duì)象然后再丟給GC。因?yàn)槭莻髦?,這里的o是個(gè)調(diào)用時(shí)候的拷貝,會(huì)不會(huì)無法回收?不就是拷貝嗎,退出方法什么都沒了,這個(gè)對(duì)象怎么會(huì)留的住。盡量避免型classA{Bb=newB(this);}classB{Aa;B(Aa)}這個(gè)存在互相引用,可能導(dǎo)致孤島現(xiàn)象,不過這個(gè)不會(huì)造成內(nèi)存泄露不過我自己覺得這個(gè)會(huì)降低GC的效率,就從我的智力來看,我覺得這種情況比一
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 關(guān)于推進(jìn)項(xiàng)目進(jìn)度的工作簡報(bào)
- 年度財(cái)務(wù)報(bào)表及審計(jì)結(jié)果
- 河南省駐馬店市部分學(xué)校2024-2025學(xué)年高三下學(xué)期3月月考地理試題(含答案)
- 基于區(qū)塊鏈技術(shù)的農(nóng)業(yè)溯源體系構(gòu)建方案
- 服裝設(shè)計(jì)與制造業(yè)務(wù)外包合作協(xié)議
- 個(gè)性化培訓(xùn)計(jì)劃實(shí)施效果分析表
- 網(wǎng)絡(luò)優(yōu)化服務(wù)升級(jí)合作協(xié)議
- 汽車采購銷售合同書及保修條款
- 智能醫(yī)療項(xiàng)目合作協(xié)議
- 企業(yè)危機(jī)管理機(jī)制構(gòu)建與運(yùn)行
- 部編人教版九年級(jí)下冊(cè)語文-第5單元-17-屈原-課件-課件
- 2024版PLC控制系統(tǒng)合同
- 2024年公需科目培訓(xùn)考試題及答案
- 2024年全國國家電網(wǎng)招聘之電網(wǎng)計(jì)算機(jī)考試經(jīng)典測(cè)試題(附答案)
- GB 18584-2024家具中有害物質(zhì)限量
- Module 2 Unit 2 It will snow in Harbin.(教學(xué)設(shè)計(jì))-2023-2024學(xué)年外研版(三起)英語六年級(jí)下冊(cè)
- DL-T-5115-2016混凝土面板堆石壩接縫止水技術(shù)規(guī)范
- 兒童孤獨(dú)癥的視覺注意力與視覺加工
- 中國古都西安英文介紹課件
- 第3課 中古時(shí)期的西歐(新教材課件)-【中職專用】《世界歷史》(高教版2023?基礎(chǔ)模塊)
- 《電氣裝置安裝工程 盤、柜及二次回路接線施工及驗(yàn)收規(guī)范》
評(píng)論
0/150
提交評(píng)論