effective java 第三版 條目7 排除不需要的對象引用

? ? ? 如果你是從一個需要手動內(nèi)存管理的程序員(c/c++)轉(zhuǎn)到一個由自動內(nèi)存管理的程序員(java)钧惧,你的工作會更加簡單酱床。因?yàn)槟阈枰膶ο髸詣釉偕?dāng)你想要使用它的時(shí)候。這看起來很魔幻當(dāng)你第一次體驗(yàn)自動內(nèi)存管理康栈,他很很容易給人一種你需要記住內(nèi)存管理這件事的印象述吸。但是,這肯定是不正確的扼劈!

? ?思考這樣一段棧實(shí)現(xiàn)的代碼:

// Can you spot the "memory leak"?

public class Stack {

? ?? ?private Object[] elements; private int size = 0;

? ?? ?private static final int DEFAULT_INITIAL_CAPACITY = 16;

? ?? ?public Stack() {

? ? ?? ?elements = new Object[DEFAULT_INITIAL_CAPACITY];

? ?? ?}

? ?? ?public void push(Object e) { ensureCapacity(); elements[size++] = e;

? ?}

? ?public Object pop() { if (size == 0)

? ?? ?? ?throw new EmptyStackException(); return elements[--size];

? ?}

? ?/*

? ?Ensure space for at least one more element, roughly doubling the capacity each time the array needs to grow.

?*? /

? ? private void ensureCapacity() { if (elements.length == size)

? ? ? ? ?elements =?Arrays.copyOf(elements,?2 size +?1);

? ? }

}

? ? 這段程序完全沒有錯誤(但是看一看條目29中類的版本)驻啤。你應(yīng)該盡可能地測試一下它,它將順利的通過所有的測試荐吵,但是這里仍然有一個潛在的問題骑冗。寬泛地說,這個程序有一個“內(nèi)存泄漏”的問題先煎,他可能導(dǎo)致提高垃圾回收的行為而靜悄悄地減少性能贼涩,在極端的情況下,他會導(dǎo)致OutOfMemoryError薯蝎,但是這樣一個失敗是很少見的遥倦!

? ? ? 那這里真的有內(nèi)存泄漏嗎?如果一個棧增長然后又收縮占锯,這些本來被pop掉的對象仍然在棧中袒哥,他們沒有被垃圾回收清理掉,盡管這個程序使用的棧不會再使用這些對象消略。這是因?yàn)闂0愡@些對象的引用堡称,一個廢棄的引用簡單來說是沒有地方再引用它,在這個問題上疑俭,在任何活動部分之外的引用是廢棄的粮呢,而活動范圍則是在這個棧的size小的部分!

? ?內(nèi)存泄漏在垃圾回收語言(更是當(dāng)?shù)卣f是不關(guān)注對象保留)總是潛在的。如果一個對象引用不關(guān)注它是否保存钞艇,不只是這個對象被垃圾回收排除掉,同時(shí)也關(guān)注一個對象的引用等等豪硅。甚至吐過很少的對象引用不小心被保存類哩照,許多對象可能會由于高好費(fèi)的垃圾回收而無法創(chuàng)建!

? ?這個問題的固定解法很簡單:只要一個引用被標(biāo)記為nul就可以類懒浮。在這個棧的例子中飘弧,當(dāng)這個對象從棧中pop之后识藤,那么這個兌現(xiàn)個引用到這個對象就被廢棄!這個正確的pop方法的版本是這樣:

public Object pop() {

? ? ?if (size == 0)

? ? ? ? ? ?throw new EmptyStackException();?

? ? ?Object result = elements[--size];

? ? ?elements[size] = null; // Eliminate obsolete reference

? ? ?return result;

}

? ?一個賦予null值的額外的好處是這個廢棄的引用不會因?yàn)槭д`而被關(guān)聯(lián)到對象上次伶!這段程序?qū)ⅠR通過空指針異常失敗痴昧,而不是靜靜地保持錯誤。這樣做總是對盡可能地找到程序中的錯誤是有好處的冠王!

? ?當(dāng)程序員第一次被這種錯誤傷害赶撰,他們可能過度地將在每次使用完一個對象之后將每一個對象引用賦予Null值,但是這樣做既不必要柱彻,也不是令人滿意的豪娜!賦予Null值的對象引用應(yīng)該是一種例外而不是一種標(biāo)準(zhǔn)。最好的方式來排除一個廢棄的對象哟楷,是改變來控制引用不會調(diào)出一個范圍內(nèi)瘤载,這通常發(fā)生在當(dāng)你每次你在你將對象定義在一個最狹隘的范圍中(條目57)。

? ?所以什么時(shí)候你應(yīng)該將一個引用賦值為null呢卖擅?又是這個棧類的哪一個方面影響出內(nèi)存泄露呢鸣奔?簡單來說,這是因?yàn)槌徒祝瑮V袛?shù)組的內(nèi)存是由它自己管理溃蔫!這個存儲池由一個有多個element的數(shù)組組成,這些element在數(shù)組被分配的活動范圍之內(nèi)琳猫,然后剩余的數(shù)組部分就是空的伟叛。但是垃圾回收不知道這些事情!對于垃圾回收器來說脐嫂,數(shù)組中所有的element都是相等的统刮,只有程序員才知道哪些活動范圍內(nèi)的element是不重要的。所以程序員需要在這數(shù)組中的element變得不重要了就要將他們賦予null值账千。

? 通常來說侥蒙,無論是不是一個類管理它自己的內(nèi)存,程序員都應(yīng)該注意到內(nèi)存泄露的問題匀奏。無論什么時(shí)候鞭衩,一個element不會再使用了,所有包含他的對象引用都應(yīng)該被賦予null值娃善。

? ?? 另一個常見的內(nèi)存泄露是緩存论衍。一旦你放了一個對象的引用到一個緩存,很容易就會忘記它在緩存中而導(dǎo)致這個對象在沒有用之后還長時(shí)間留在緩存中聚磺。這里對這個問題有幾個方案坯台。如果你很幸運(yùn)可以去實(shí)現(xiàn)一個緩存,你確定這個緩存會有一些緩存在廢棄之后還會存在緩存之內(nèi)瘫寝,使用WeakHashMap來實(shí)現(xiàn)這個緩存蜒蕾。這些Map中的實(shí)體將會在廢棄之后被自動移除稠炬。記住這個WeakHashMap將會非常有用,但是僅當(dāng)確定這個緩存的鍵可能會廢棄咪啡,而Map中的值首启。

? ? ?更常見的是,這個緩存變得沒有價(jià)值之前的使用時(shí)間很少被定義撤摸,在某些狀況之下毅桃,可能偶爾會很清楚地知道一個緩存的實(shí)體已經(jīng)變得不可用了。這個可能會是在后臺線程需要做的工作愁溜。LinkedHashMap使用它的removeEldestEntry 提供了一個的方案疾嗅。但是,對于很多復(fù)雜的緩存你可能需要首先使用java.lang.ref來解決問題冕象。

? ? 第三個可能內(nèi)存泄露的地方是監(jiān)聽器和回調(diào)函數(shù)代承,如果你實(shí)現(xiàn)了這個客戶端注冊回調(diào)函數(shù)的API,但是沒有明確地將他們撤銷注冊渐扮,他們將會堆砌起來除非你對它們做一些事论悴。一個方式是敏捷地確認(rèn)這些回調(diào)函數(shù)已經(jīng)被垃圾回收器標(biāo)記為弱引用。例如對于實(shí)例墓律,將他們以鍵的形式存儲在WeakHashMap膀估。因?yàn)閮?nèi)存泄露通常不會因?yàn)橥耆某绦虺鲥e而表現(xiàn)出來,他們通常會存在一個系統(tǒng)幾年耻讽,它們通常只會在仔細(xì)的代碼檢查中或者借用有機(jī)制的代碼調(diào)試工具(比如說heap profiler)才會被發(fā)現(xiàn)察纯。因此,在這種問題出現(xiàn)之前預(yù)先去學(xué)習(xí)知道這個問題通常是很讓人滿意的针肥!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末饼记,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子慰枕,更是在濱河造成了極大的恐慌具则,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件具帮,死亡現(xiàn)場離奇詭異博肋,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蜂厅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進(jìn)店門匪凡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人葛峻,你說我怎么就攤上這事锹雏。” “怎么了术奖?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵礁遵,是天一觀的道長。 經(jīng)常有香客問我采记,道長佣耐,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任唧龄,我火速辦了婚禮兼砖,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘既棺。我一直安慰自己讽挟,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布丸冕。 她就那樣靜靜地躺著耽梅,像睡著了一般。 火紅的嫁衣襯著肌膚如雪胖烛。 梳的紋絲不亂的頭發(fā)上眼姐,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天,我揣著相機(jī)與錄音佩番,去河邊找鬼众旗。 笑死,一個胖子當(dāng)著我的面吹牛趟畏,可吹牛的內(nèi)容都是我干的贡歧。 我是一名探鬼主播,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼赋秀,長吁一口氣:“原來是場噩夢啊……” “哼利朵!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起沃琅,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤哗咆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后益眉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體晌柬,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年郭脂,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了年碘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡展鸡,死狀恐怖屿衅,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情莹弊,我是刑警寧澤涤久,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布涡尘,位于F島的核電站,受9級特大地震影響响迂,放射性物質(zhì)發(fā)生泄漏考抄。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一蔗彤、第九天 我趴在偏房一處隱蔽的房頂上張望川梅。 院中可真熱鬧,春花似錦然遏、人聲如沸贫途。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽丢早。三九已至,卻和暖如春诫给,著一層夾襖步出監(jiān)牢的瞬間香拉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工中狂, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留凫碌,地道東北人。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓胃榕,卻偏偏與公主長得像盛险,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子勋又,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法苦掘,類相關(guān)的語法,內(nèi)部類的語法楔壤,繼承相關(guān)的語法鹤啡,異常的語法,線程的語...
    子非魚_t_閱讀 31,623評論 18 399
  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結(jié)構(gòu)(3).初始化時(shí)...
    歐辰_OSR閱讀 29,373評論 8 265
  • 小緣是一個年輕的媽媽蹲嚣,每天的重心就是照顧不滿周歲的兒子递瑰,要管好孩子的一日三餐,體格鍛煉隙畜,引導(dǎo)孩子言語發(fā)展抖部。每天下午...
    無人空巷閱讀 297評論 0 0
  • 2015-04-15 Y姐的故事:從帝都到馬里蘭 Y姐絕對是我們眼中的人生贏家或是白富美。從我們那里最好的高中议惰,走...
    一時(shí)佛在閱讀 1,118評論 0 3
  • 完了完了 最近社團(tuán)里面來了一個小哥哥 叫崔旭 新傳院學(xué)播音主持的 很優(yōu)秀 怎么辦好像有點(diǎn)點(diǎn)喜歡他 昂 我的媽呀 但...
    蔡漫漫閱讀 276評論 0 0