第6條 消除過期的對象引用

圖1

如圖所示的例子揍障,這段程序中沒有明顯的錯誤,但是存在一個隱藏的問題(“內存泄漏”)畸冲,隨著垃圾回收活動的增加,或者由于內存占用的不斷增加观腊,程序性能的降低會逐漸表現(xiàn)出來邑闲,在極端的情況下,這種內存泄漏會導致磁盤交換梧油,甚至導致程序失敗苫耸。

如果棧先是增長,然后在收縮儡陨,那么從棧中彈出的對象不會被當做垃圾回收褪子,即使使用棧的程序不在引用這些對象,他們也不會被回收骗村。因為嫌褪,棧內部維護著對這些對象的過期引用。過期引用是指永遠也不會解除的引用胚股。在以上這個例子中笼痛,elements數組的活動部分之外的所有引用都是過期的。活動部分是指elements數組中下標小于size的部分缨伊。

如果一個對象引用被無意識的保留下來摘刑,那么垃圾回收機制不僅不會處理這個對象,而且也不會處理處理這個對象所引用的所有其他對象刻坊。即使少量的幾個對象被無意識的保留下來枷恕,也許會有許多對象被排除在垃圾回收之外,并由此對性能造成重大影響谭胚。

解決方法:一旦引用對象已經過期徐块,清空這些引用。

例子中的statck類漏益,只要一個單元被彈出蛹锰,指向他的引用就過期了,pop方法修改為

public object pop(){

if(size ==0){

throw new EmptyStackException();

}

ObJect result = elements[--size]//--放在前面為先減一再使用

element[size] = null;

return result;

}

清空過期引用的另外一個好處是绰疤,如果他們以后又被錯誤的解除引用铜犬,程序會立即拋出空指針異常,而不是悄悄的錯誤的運行下去轻庆。

清空對象引用應該是一種例外癣猾,而不是一種規(guī)范行為。消除過期引用的最好的方法是讓包含該引用的變量結束其生命周期余爆。如果在最緊湊的作用域范圍內定義一個變量

如下例 1

Iterator iter = l.iterator();

while(iter.hasNext()){

String str = (String) iter.next();

System.out.println(str);

}

例2

while(Iterator iter = l.iterator();iter.hasNext()){

String str = (String) iter.next();

System.out.println(str);

}

例2這種就比較合適纷宇,iter的生命周期循環(huán)結束后結束

stack類自己管理內存,存儲池包含了elements數組的元素蛾方,數組活動區(qū)域中的元素是已分配的像捶,而數組其余部分的元素是自由的,但是垃圾回收器并不知道這一點桩砰,對于垃圾回收來說拓春,elements數組中的所有對象引用都同等有效。只有我們本身知道數組的非活動部分是不重要的亚隅,所以需要我們手動清空這些元素硼莽。

一般而言,只要是自己管理內存煮纵,就應該警惕內存泄漏問題懂鸵。一旦元素被釋放掉,則該元素中包含的任何對象引用都應被清空掉行疏。


內存泄漏的另一個常見的來源是緩存匆光,一旦把對象引用放入緩存中,它就很容易被遺忘隘擎。對于這種情況有幾種可能的解決方案殴穴,如果你正好要實現(xiàn)一個只要在緩存之外存在對某個項的鍵的引用,該項就有意義這樣的緩存的話货葬,就可以使用WeakHashMap代表緩存采幌,因為當緩存中的項過期的時候,它們就會自動被刪除掉震桶。但是只有當所要的緩存項的生命周期是由key的外部引用而不是由value決定時WeakHashMap才有用處休傍。

更常見的情況是“緩存項的生命周期是否有意義”,并不是很容易確定蹲姐,隨著時間的推移磨取,其中的項會變得越來越沒有價值,在這種情況下柴墩,緩存應該時不時地清除掉沒用的項忙厌,這種工作可以交給一個后臺線程(可能是Timer或者ScheduledThreadPoolExecutor)來完成,或者也可以在給緩存添加新條目的時候順便進行江咳。LinkedHashMap類利用它的removeEldestEntry方法可以很容易的實現(xiàn)后一種方案逢净,對于更加復雜的緩存,就只能直接使用java.lang.ref了歼指。

內存泄漏的第三種常見來源是監(jiān)聽器和其他的回調函數爹土。如果客戶在你實現(xiàn)的API中注冊回調,但是卻沒有顯示取消注冊踩身。那么除非你采取些手段胀茵,否則它們就會積聚。確毙瑁回調立即被當作垃圾的最佳方法是只保存它們的弱引用琼娘,例如,只將他們保存為WeakHashMap中的鍵附鸽。

WeakHashmap 的簡單介紹

1. 以弱鍵 實現(xiàn)的基于哈希表的 Map脱拼。在 WeakHashMap 中,當某個鍵不再正常使用時拒炎,將自動移除其條目挪拟。更精確地說,對于一個給定的鍵击你,其映射的存在并不阻止垃圾回收器對該鍵的丟棄玉组,這就使該鍵成為可終止的,被終止丁侄,然后被回收惯雳。丟棄某個鍵時,其條目從映射中有效地移除

2. WeakHashMap 類的行為部分取決于垃圾回收器的動作鸿摇。因為垃圾回收器在任何時候都可能丟棄鍵石景,WeakHashMap 就像是一個被悄悄移除條目的未知線程。特別地,即使對 WeakHashMap 實例進行同步潮孽,并且沒有調用任何賦值方法揪荣,在一段時間后 size 方法也可能返回較小的值,對于 isEmpty 方法往史,返回 false仗颈,然后返回true,對于給定的鍵椎例,containsKey 方法返回 true 然后返回 false挨决,對于給定的鍵,get 方法返回一個值订歪,但接著返回 null脖祈,對于以前出現(xiàn)在映射中的鍵,put 方法返回 null刷晋,而 remove 方法返回 false盖高,對于鍵 set、值 collection 和條目 set 進行的檢查掏秩,生成的元素數量越來越少或舞。

3. WeakHashMap 中的每個鍵對象間接地存儲為一個弱引用的指示對象。因此蒙幻,不管是在映射內還是在映射之外映凳,只有在垃圾回收器清除某個鍵的弱引用之后,該鍵才會自動移除邮破。

例3

BufferedReader br=newBufferedReader(newFileReader(file));//構造一個BufferedReader類來讀取文件

String s =null;

String s1 =""

while((s = br.readLine())!=null){//使用readLine方法诈豌,一次讀一行

s1 = s1+s

result.append(System.lineSeparator()+s);

}

此例是曾經寫過的一個列子,用s用來讀取文件中的行的內容抒和,用s1進行接收矫渔,當文件中的內容過多時,會導致內存溢出

PS:補充一下堆棧的基礎知識摧莽。

棧(stack)庙洼,有時候我們也稱為堆棧(這一點可能會讓很多小伙伴迷茫)。是由操作系統(tǒng)自動分配和釋放的镊辕,用來存放局部變量油够,基本類型的值(比如int,char征懈,boolean等)石咬,因為它是操作系統(tǒng)自動分配和釋放的,所以通常我們看不到棧的操作卖哎。另外鬼悠,棧是先進先出的删性。

堆(heap)。由程序員自己來分配和釋放焕窝。用來存放用new創(chuàng)建的對象和數組蹬挺。注意,前面我們說了“由程序員自己來分配和釋放”袜啃,實際上在Java里面汗侵,是由程序員自己來分配的(new)幸缕,但是不是由程序員自己來釋放的群发,而是通過GC(垃圾回收器)來完成釋放的,程序員完全感知不到发乔。

方法區(qū)(method)熟妓。又叫靜態(tài)區(qū),用來存放在整個程序中都是唯一的元素栏尚,比如所有的class起愈,以及static變量

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市译仗,隨后出現(xiàn)的幾起案子抬虽,更是在濱河造成了極大的恐慌,老刑警劉巖纵菌,帶你破解...
    沈念sama閱讀 222,627評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件阐污,死亡現(xiàn)場離奇詭異,居然都是意外死亡咱圆,警方通過查閱死者的電腦和手機笛辟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來序苏,“玉大人手幢,你說我怎么就攤上這事〕老辏” “怎么了围来?”我有些...
    開封第一講書人閱讀 169,346評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長匈睁。 經常有香客問我监透,道長,這世上最難降的妖魔是什么软舌? 我笑而不...
    開封第一講書人閱讀 60,097評論 1 300
  • 正文 為了忘掉前任才漆,我火速辦了婚禮,結果婚禮上佛点,老公的妹妹穿的比我還像新娘醇滥。我一直安慰自己黎比,他們只是感情好,可當我...
    茶點故事閱讀 69,100評論 6 398
  • 文/花漫 我一把揭開白布鸳玩。 她就那樣靜靜地躺著阅虫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪不跟。 梳的紋絲不亂的頭發(fā)上颓帝,一...
    開封第一講書人閱讀 52,696評論 1 312
  • 那天,我揣著相機與錄音窝革,去河邊找鬼购城。 笑死,一個胖子當著我的面吹牛虐译,可吹牛的內容都是我干的瘪板。 我是一名探鬼主播,決...
    沈念sama閱讀 41,165評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼漆诽,長吁一口氣:“原來是場噩夢啊……” “哼侮攀!你這毒婦竟也來了?” 一聲冷哼從身側響起厢拭,我...
    開封第一講書人閱讀 40,108評論 0 277
  • 序言:老撾萬榮一對情侶失蹤兰英,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后供鸠,有當地人在樹林里發(fā)現(xiàn)了一具尸體畦贸,經...
    沈念sama閱讀 46,646評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,709評論 3 342
  • 正文 我和宋清朗相戀三年回季,在試婚紗的時候發(fā)現(xiàn)自己被綠了家制。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,861評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡泡一,死狀恐怖颤殴,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情鼻忠,我是刑警寧澤涵但,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站帖蔓,受9級特大地震影響矮瘟,放射性物質發(fā)生泄漏。R本人自食惡果不足惜塑娇,卻給世界環(huán)境...
    茶點故事閱讀 42,196評論 3 336
  • 文/蒙蒙 一澈侠、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧埋酬,春花似錦哨啃、人聲如沸烧栋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽审姓。三九已至,卻和暖如春祝峻,著一層夾襖步出監(jiān)牢的瞬間魔吐,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評論 1 274
  • 我被黑心中介騙來泰國打工莱找, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留酬姆,地道東北人。 一個月前我還...
    沈念sama閱讀 49,287評論 3 379
  • 正文 我出身青樓宋距,卻偏偏與公主長得像轴踱,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子谚赎,可洞房花燭夜當晚...
    茶點故事閱讀 45,860評論 2 361

推薦閱讀更多精彩內容

  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法诱篷,內部類的語法壶唤,繼承相關的語法,異常的語法棕所,線程的語...
    子非魚_t_閱讀 31,665評論 18 399
  • 問題的引出 這段程序有一個“內存泄露”闸盔,隨著GC活動的增加,或者由于內存占用的不斷增加琳省,程序性能降低會逐漸表現(xiàn)出來...
    每天學點編程閱讀 520評論 0 4
  • Java引用的種類 1.對象在內存中的狀態(tài) 對于JVM的垃圾回收機制來說迎吵,是否回收一個對象的標準在于:是否還有引用...
    Jack921閱讀 3,866評論 0 3
  • 從三月份找實習到現(xiàn)在,面了一些公司针贬,掛了不少击费,但最終還是拿到小米、百度桦他、阿里蔫巩、京東、新浪快压、CVTE圆仔、樂視家的研發(fā)崗...
    時芥藍閱讀 42,278評論 11 349
  • 放寒假我和媽媽去外婆家度假,外婆家有很多好玩的蔫劣、好吃的坪郭。我每天都要去探索。有一天我發(fā)現(xiàn)脉幢,剛吃完食的公雞卻在吃石子我...
    靈濟四2閱讀 301評論 0 1