国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

內(nèi)存泄漏,走開 輕松搞定Java內(nèi)存泄漏

2019-11-18 11:13:01
字體:
供稿:網(wǎng)友
抽象

  盡管java虛擬機(jī)和垃圾回收機(jī)制治理著大部分的內(nèi)存事務(wù),但是在java軟件中還是可能存在內(nèi)存泄漏的情況。的確,在大型工程中,內(nèi)存泄漏是一個普遍問題。避免內(nèi)存泄漏的第一步,就是要了解他們發(fā)生的原因。這篇文章就是要介紹一些常見的缺陷,然后提供一些非常好的實(shí)踐例子來指導(dǎo)你寫出沒有內(nèi)存泄漏的代碼。一旦你的程序存在內(nèi)存泄漏,要查明代碼中引起泄漏的原因是很困難的。同時這篇文章也要介紹一個新的工具來查找內(nèi)存泄漏,然后指明發(fā)生的根本原因。這個工具輕易上手,可以讓你找到產(chǎn)品級系統(tǒng)中的內(nèi)存泄漏。

  垃圾回收(GC)的角色

  雖然垃圾回收關(guān)心著大部分的問題,包括內(nèi)存治理,使得程序員的任務(wù)顯得更加輕松,但是程序員還是可能犯些錯誤導(dǎo)致內(nèi)存泄漏問題。GC(垃圾回收)通過遞歸對所有從"根"對象(堆棧中的對象,靜態(tài)數(shù)據(jù)成員,JNI句柄等等)繼續(xù)下來的引用進(jìn)行工作,然后標(biāo)記所有可以訪問的活著的對象。而這些對象變成了程序唯一能夠操縱的對象,其他的對象都被釋放了。因?yàn)镚C使得程序不能夠訪問那些被釋放的對象,所以這樣做是安全的。

  內(nèi)存治理可以說是自動的,但是這并沒有讓程序員脫離內(nèi)存治理問題。比方說,對于內(nèi)存的分配(還有釋放)總是存在一定的開銷,盡管這些開銷對程序員來說是暗含的。一個程序假如創(chuàng)建了很多對象,那么它就要比完成相同任務(wù)而創(chuàng)建了較少對象的程序執(zhí)行的速度慢(其他提供的內(nèi)容都相同)。

  導(dǎo)致內(nèi)存泄漏主要的原因是,先前申請了內(nèi)存空間而忘記了釋放。假如程序中存在對無用對象的引用,那么這些對象就會駐留內(nèi)存,消耗內(nèi)存,因?yàn)闊o法讓垃圾回收器驗(yàn)證這些對象是否不再需要。正如我們前面看到的,假如存在對象的引用,這個對象就被定義為"活著的",同時不會被釋放。要確定對象所占內(nèi)存將被回收,程序員就要務(wù)必確認(rèn)該對象不再會被使用。典型的做法就是把對象數(shù)據(jù)成員設(shè)為null或者從集合中移除該對象。注重,當(dāng)局部變量不需要時,不需明顯的設(shè)為null,因?yàn)橐粋€方法執(zhí)行完畢時,這些引用會自動被清理。

  從更高一個層次看,這就是所有存在內(nèi)存管的語言對內(nèi)存泄漏所考慮的事情,剩余的對象引用將不再會被使用。

  典型泄漏

  既然我們知道了在java中確實(shí)會存在內(nèi)存泄漏,那么就讓我們看一些典型的泄漏,并找出他們發(fā)生的原因。

  全局集合

  在大型應(yīng)用程序中存在各種各樣的全局?jǐn)?shù)據(jù)倉庫是很普遍的,比如一個JNDI-tree或者一個session table。在這些情況下,注重力就被放在了治理數(shù)據(jù)倉庫的大小上。當(dāng)然是有一些適當(dāng)?shù)臋C(jī)制可以將倉庫中的無用數(shù)據(jù)移除。

  可以有很多不同的解決形式,其中最常用的是一種周期運(yùn)行的清除作業(yè)。這個作業(yè)會驗(yàn)證倉庫中的數(shù)據(jù)然后清除一切不需要的數(shù)據(jù)。
另一個辦法是使用引用計(jì)算。集合用來對了解每個集合入口關(guān)聯(lián)器(referrer)的數(shù)目負(fù)責(zé)。這要求關(guān)聯(lián)器通知集合什么時候完成進(jìn)入。當(dāng)關(guān)聯(lián)器的數(shù)目為零時,就可以移除集合中的相關(guān)元素。

  高速緩存

  高速緩存是一種用來快速查找已經(jīng)執(zhí)行過的操作結(jié)果的數(shù)據(jù)結(jié)構(gòu)。因此,假如一個操作執(zhí)行很慢的話,你可以先把普通輸入的數(shù)據(jù)放入高速緩存,然后過些時間再調(diào)用高速緩存中的數(shù)據(jù)。

  高速緩存多少還有一點(diǎn)動態(tài)實(shí)現(xiàn)的意思,當(dāng)數(shù)據(jù)操作完畢,又被送入高速緩存。一個典型的算法如下所示:

  1.檢查結(jié)果是否在高速緩存中,存在則返回結(jié)果;

  2.假如結(jié)果不在,那么計(jì)算結(jié)果;

  3.將結(jié)果放入高速緩存,以備將來的操作調(diào)用。

  這個算法的問題(或者說潛在的內(nèi)存泄漏)在最后一步。假如操作伴隨著一個不同的,輸入非常大的數(shù)字,那么存入高速緩存的也是一個非常大的結(jié)果。那么這個方法就不是能夠勝任的了。

  為了避免這種潛在的致命錯誤設(shè)計(jì),程序就必須確定高速緩存在他所使用的內(nèi)存中有一個上界。因此,更好的算法是:

  1.檢查結(jié)果是否在高速緩存中,存在則返回結(jié)果;

  2.假如結(jié)果不在,那么計(jì)算結(jié)果;

  3.假如高速緩存所占空間過大,移除緩存中舊的結(jié)果;

  4.將結(jié)果放入高速緩存,以備將來的操作調(diào)用。

  通過不斷的從緩存中移除舊的結(jié)果,我們可以假設(shè),將來,最新輸入的數(shù)據(jù)可能被重用的幾率要遠(yuǎn)遠(yuǎn)大于舊的結(jié)果。這通常是一個不錯的設(shè)想。

  這個新的算法會確保高速緩存的容量在預(yù)先確定的范圍內(nèi)。精確的范圍是很難計(jì)算的,因?yàn)榫彺嬷械膶ο蟠嬖谝脮r將繼續(xù)有效。正確的劃分高速緩存的大小是一個復(fù)雜的任務(wù),你必須權(quán)衡可使用內(nèi)存大小和數(shù)據(jù)快速存取之間的矛盾。

  另一個解決這個問題的途徑是使用java.lang.ref.SoftReference類堅(jiān)持將對象放入高速緩存。這個方法可以保證當(dāng)虛擬機(jī)用完內(nèi)存或者需要更多堆的時候,可以釋放這些對象的引用。

  類裝載器

  Java類裝載器創(chuàng)建就存在很多導(dǎo)致內(nèi)存泄漏的漏洞。由于類裝載器的復(fù)雜結(jié)構(gòu),使得很難得到內(nèi)存泄漏的透視圖。這些困難不僅僅是由于類裝載器只與"普通的"對象引用有關(guān),同時也和對象內(nèi)部的引用有關(guān),比如數(shù)據(jù)變量,方法和各種類。這意味著只要存在對數(shù)據(jù)變量,方法,各種類和對象的類裝載器,那么類裝載器將駐留在JVM中。既然類裝載器可以同很多的類關(guān)聯(lián),同時也可以和靜態(tài)數(shù)據(jù)變量關(guān)聯(lián),那么相當(dāng)多的內(nèi)存就可能發(fā)生泄漏。

  定位內(nèi)存泄漏

  經(jīng)常地,程序內(nèi)存泄漏的最初跡象發(fā)生在出錯之后,得到一個OutOfMemoryError在你的程序中。這種典型地情況發(fā)生在產(chǎn)品環(huán)境中,而在那里,你希望內(nèi)存泄漏盡可能的少,調(diào)試的可能性也達(dá)到最小。也許你的測試環(huán)境和產(chǎn)品的系統(tǒng)環(huán)境不盡相同,導(dǎo)致泄露的只會在產(chǎn)品中揭示。這種情況下,你需要一個低內(nèi)務(wù)操作工具來監(jiān)聽和尋找內(nèi)存泄漏。同時,你還需要把這個工具同你的系統(tǒng)聯(lián)系起來,而不需要重新啟動他或者機(jī)械化你的代碼。也許更重要的是,當(dāng)你做分析的時候,你需要能夠同工具分離而使得系統(tǒng)不會受到干擾。

  一個OutOfMemoryError經(jīng)常是內(nèi)存泄漏的一個標(biāo)志,有可能應(yīng)用程序的確用了太多的內(nèi)存;這個時候,你既不能增加JVM的堆的數(shù)量,也不能改變你的程序而使得他減少內(nèi)存使用。但是,在大多數(shù)情況下,一個OutOfMemoryError是內(nèi)存泄漏的標(biāo)志。一個解決辦法就是繼續(xù)監(jiān)聽GC的活動,看看隨時間的流逝,內(nèi)存使用量是否會增加,假如有,程序中一定存在內(nèi)存泄漏。

  具體輸出

  有很多辦法來監(jiān)聽垃圾回收器的活動。也許運(yùn)用最廣泛的就是以:-Xverbose:gc選項(xiàng)運(yùn)行JVM,然后觀察輸出結(jié)果一段時間。

[memory] 10.109-10.235: GC 65536K->16788K (65536K), 126.000 ms

  箭頭后的值(在這個例子中 16788K)是垃圾回收后堆的使用量。

  控制臺

  觀察這些無盡的GC具體統(tǒng)計(jì)輸出是一件非常單調(diào)乏味的事情。好在有一些工具來代替我們做這些事情。The JRockit Management Console可以用圖形的方式輸出堆的使用量。通過觀察圖像,我們可以很方便的觀察堆的使用量是否伴隨時間增長。



發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 枣强县| 通辽市| 铅山县| 肇州县| 宜阳县| 星座| 姚安县| 长汀县| 朔州市| 集安市| 永修县| 年辖:市辖区| 孝昌县| 民丰县| 西林县| 稷山县| 固阳县| 正蓝旗| 东乡族自治县| 凉城县| 阜平县| 五寨县| 揭西县| 五莲县| 乌海市| 菏泽市| 张北县| 扎囊县| 平遥县| 三门县| 仙桃市| 济阳县| 海口市| 汝南县| 青川县| 沛县| 东兴市| 邢台市| 东兰县| 平乡县| 杭锦旗|