成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

第7項(xiàng):清除過期對(duì)象的引用

stormgens / 2510人閱讀

摘要:具有垃圾收集功能的編程語言中的內(nèi)存泄漏更恰當(dāng)?shù)胤Q為無意識(shí)的對(duì)象保留是隱蔽的。清空對(duì)象引用應(yīng)該是一種例外,而不是一種規(guī)范行為。消除過期引用最好的方法是讓包含該引用的變量結(jié)束其生命周期。

??當(dāng)你從手工管理內(nèi)存的語言(比如C或者C++)轉(zhuǎn)換到具有垃圾回收功能的語言的時(shí)候,程序猿的工作就會(huì)變得更加容易,因?yàn)楫?dāng)你用完了對(duì)象之后,他們就會(huì)被自動(dòng)回收。當(dāng)你第一次經(jīng)歷對(duì)象回收功能的時(shí)候,會(huì)覺得這簡(jiǎn)直有點(diǎn)不可思議。這很容易給你留下這樣的印象,認(rèn)為自己不再需要考慮內(nèi)存管理的事情了,其實(shí)不然。

??考慮下面這個(gè)簡(jiǎn)單的棧實(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);
    }
}

??這個(gè)程序沒有明顯的錯(cuò)誤(它的通用版本請(qǐng)見29項(xiàng))。無論如何測(cè)試,它都會(huì)成功地通過每一項(xiàng)測(cè)試,但是這個(gè)程序中隱藏著一個(gè)問題。簡(jiǎn)而言之,改程序存在“內(nèi)存泄漏”,由于垃圾收集器的活動(dòng)增加或者內(nèi)存占用增加,程序性能的降低會(huì)逐漸表現(xiàn)出來。在極端的情況下,這種內(nèi)存泄漏會(huì)導(dǎo)致磁盤分頁(Disk Paging),甚至導(dǎo)致程序失敗并出現(xiàn)OutOfMemoryError,但這種失敗情形相對(duì)比較少見。

??那么,程序中哪里發(fā)生了內(nèi)存泄漏呢?如果一個(gè)棧先是增長(zhǎng),然后再收縮,那么,從棧中彈出來的對(duì)象將不會(huì)被當(dāng)做垃圾回收,即使使用棧的程序不再引用這些對(duì)象,它們也不會(huì)回收,因?yàn)椋瑮?nèi)部維護(hù)著對(duì)這些對(duì)象的過期引用(obsolete references),所謂的過期引用,是指永遠(yuǎn)也不會(huì)再被解除的引用。在本例中,凡是在element數(shù)組的“活動(dòng)部分”(active portion)之外的任何引用都是過期的。活動(dòng)部分是指element中下標(biāo)小于size的那些元素。

??具有垃圾收集功能的編程語言中的內(nèi)存泄漏(更恰當(dāng)?shù)胤Q為無意識(shí)的對(duì)象保留)是隱蔽的。如果無意中保留了對(duì)象引用,則不僅將該對(duì)象從垃圾回收中排除,而且該對(duì)象引用的任何對(duì)象也是如此,依此類推。即使無意中保留了少量對(duì)象引用,也會(huì)阻止許多對(duì)象被垃圾回收器收集,對(duì)性能可能產(chǎn)生很大影響。

??這類問題的修復(fù)方法很簡(jiǎn)單:一旦對(duì)象引用已經(jīng)過期,只需要清空這些引用即可。對(duì)于上述例子中的Stack類而言,只要一個(gè)單元被彈出棧,指向它的引用就過期了,pop方法的修訂版本如下所示:

public Object pop() {
    if (size == 0)
        throw new EmptyStackException();
    Object result = elements[--size];
    elements[size] = null; // Eliminate obsolete reference
    return result;
}

??清空過期引用的另一個(gè)好處是,如果它們以后又被錯(cuò)誤地解除引用,程序就會(huì)立即拋出NullPointerException異常,而不是悄悄地錯(cuò)誤運(yùn)行下去。盡快檢測(cè)出程序中的錯(cuò)誤總是有益的。

??當(dāng)程序員第一次被類似這樣的問題困擾的時(shí)候,它們往往會(huì)過分小心:對(duì)于每一個(gè)對(duì)象的引用,一旦程序不再用到它,就把它清空。其實(shí)這樣做即沒必要,也不是我們所期望的,因?yàn)檫@樣做會(huì)把程序代碼弄得很亂。清空對(duì)象引用應(yīng)該是一種例外,而不是一種規(guī)范行為。消除過期引用最好的方法是讓包含該引用的變量結(jié)束其生命周期。如果你是在最緊湊的作用域范圍內(nèi)定義每一個(gè)變量(第57項(xiàng)),這種情形就會(huì)自然而然地發(fā)生。

??那么,何時(shí)應(yīng)該清空引用呢?Stack類的哪方面特性使它易于遭受內(nèi)存泄漏的影響呢?簡(jiǎn)而言之,問題在于,Stack類自己管理內(nèi)存(manage its own memory)、存儲(chǔ)池(storage pool)包含了elements數(shù)組(對(duì)象引用單元,而不是對(duì)象本身)的元素。數(shù)組活動(dòng)區(qū)域(同前面的定義)中的元素是已分配的(allocated),而數(shù)組其余部分的元素則是自由的(free)。但是垃圾回收器無法知道這一點(diǎn);對(duì)于垃圾回收器而言,elements數(shù)組中的所有對(duì)象引用都同等有效。只有程序猿知道數(shù)組的非活動(dòng)部分是不重要的。程序猿可以把這個(gè)情況告知垃圾回收器,做法很簡(jiǎn)單:一旦數(shù)組元素變成了非活動(dòng)部分的一部分,程序猿就手動(dòng)清空這些數(shù)組元素。

??通常來說,只要類是自己管理內(nèi)存,程序猿就應(yīng)該警惕內(nèi)存泄漏問題。一旦元素被釋放掉,則該元素中包含的任何對(duì)象引用都應(yīng)該被清空。

??內(nèi)存泄漏的另一個(gè)常見來源是緩存。一旦你把對(duì)象引用放到緩存中,它就很容易被遺忘掉,從而使得它在很長(zhǎng)一段時(shí)間沒有使用,但是卻仍然留在緩存中。對(duì)于這個(gè)問題,這里有好幾種解決方案。如果你正好要實(shí)現(xiàn)這樣的緩存,只要在緩存之外存在對(duì)某個(gè)項(xiàng)的鍵的引用,該項(xiàng)就有意義,那么就可以用WeakHashMap代表緩存,當(dāng)緩存中的項(xiàng)過期之后,它們就會(huì)自動(dòng)被刪除。記住只有當(dāng)所要的緩存項(xiàng)的生命周期是由該鍵的外部引用而不是由值決定時(shí),WeakHashMap才有用處。

??更為常見的情形則是,“緩存項(xiàng)的生命周期是否有意義”并不是很容易確定,隨著時(shí)間的推移,其中的項(xiàng)會(huì)變得越來越?jīng)]有價(jià)值。在這種情況下,緩存應(yīng)該時(shí)不時(shí)地清除掉沒用的項(xiàng)。這項(xiàng)清除工作可以由一個(gè)后臺(tái)線程(可能是Timer或者ScheduledThreadPoolExecutor)來完成,或者也可以在給緩存添加新項(xiàng)的時(shí)候順便進(jìn)行清理。LinkedHashMap類利用它的removeEldestEntry方法可以很容易地實(shí)現(xiàn)后一種方案。對(duì)于更加復(fù)雜的緩存,必須直接使用java.lang.ref。

??內(nèi)存泄漏的第三個(gè)常見來源是監(jiān)聽器和其他回調(diào)。如果你實(shí)現(xiàn)了一個(gè)API,客戶端在這個(gè)API中注冊(cè)回調(diào),卻沒有顯示地取消注冊(cè),那么除非你采取某些動(dòng)作,否則他們就會(huì)積累下來。確?;卣{(diào)立即被當(dāng)做垃圾回收的最佳方法是只保存他們的弱引用(weak reference),例如,只將它們保存成WeakHashMap中的鍵。

??由于內(nèi)存泄漏通常不會(huì)表現(xiàn)出明顯的失敗跡象,所以他們可以在一個(gè)系統(tǒng)中存在很多年。往往只有通過仔細(xì)檢查代碼,或者借助于Heap剖析工具(Heap Profiler)才能發(fā)現(xiàn)內(nèi)存泄漏問題。因此,如果能在內(nèi)存泄漏發(fā)生之前就知道如何預(yù)測(cè)此類問題,并阻止它們發(fā)生,那是最好不過的了。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/77468.html

相關(guān)文章

  • 二章 創(chuàng)建和銷毀對(duì)象

    摘要:一個(gè)類可以提供一個(gè)公共靜態(tài)工廠方法,它僅僅是一第項(xiàng)遇到多個(gè)構(gòu)造器參數(shù)時(shí)要考慮使用構(gòu)建器靜態(tài)工廠和構(gòu)造器有個(gè)共同的局限性他們都不能很好地?cái)U(kuò)展到大量的可選參數(shù)。 ??本章涉及創(chuàng)建和銷毀對(duì)象,包括何時(shí)以及如何創(chuàng)建它們,何時(shí)以及如何避免創(chuàng)建它們,如何確保它們被及時(shí)銷毀,以及如何管理在銷毀之前必須進(jìn)行的清理操作。 第1項(xiàng):用靜態(tài)工廠方法代替構(gòu)造器 ??類允許客戶端獲取實(shí)例的傳統(tǒng)方法是提供公共構(gòu)造...

    Jeffrrey 評(píng)論0 收藏0
  • Effective Java 3rd.Edition 翻譯

    摘要:推薦序前言致謝第一章引言第二章創(chuàng)建和銷毀對(duì)象第項(xiàng)用靜態(tài)工廠方法代替構(gòu)造器第項(xiàng)遇到多個(gè)構(gòu)造器參數(shù)時(shí)要考慮使用構(gòu)建器第項(xiàng)用私有構(gòu)造器或者枚舉類型強(qiáng)化屬性第項(xiàng)通過私有構(gòu)造器強(qiáng)化不可實(shí)例化的能力第項(xiàng)優(yōu)先考慮依賴注入來引用資源第項(xiàng)避免創(chuàng)建不必要的對(duì)象 推薦序 前言 致謝 第一章 引言 第二章 創(chuàng)建和銷毀對(duì)象 第1項(xiàng):用靜態(tài)工廠方法代替構(gòu)造器 第2項(xiàng):遇到多個(gè)構(gòu)造器參數(shù)時(shí)要考慮使用構(gòu)建器 第...

    KoreyLee 評(píng)論0 收藏0
  • Effective Java 三版 全文翻譯

    摘要:本章中的大部分內(nèi)容適用于構(gòu)造函數(shù)和方法。第項(xiàng)其他方法優(yōu)先于序列化第項(xiàng)謹(jǐn)慎地實(shí)現(xiàn)接口第項(xiàng)考慮使用自定義的序列化形式第項(xiàng)保護(hù)性地編寫方法第項(xiàng)對(duì)于實(shí)例控制,枚舉類型優(yōu)先于第項(xiàng)考慮用序列化代理代替序列化實(shí)例附錄與第版中項(xiàng)目的對(duì)應(yīng)關(guān)系參考文獻(xiàn) effective-java-third-edition 介紹 Effective Java 第三版全文翻譯,純屬個(gè)人業(yè)余翻譯,不合理的地方,望指正,感激...

    galois 評(píng)論0 收藏0
  • 前端知識(shí)集錦1

    摘要:原文鏈接征服前端面試,僅供學(xué)習(xí)使用前端知識(shí)集錦原型我們創(chuàng)建的每一個(gè)函數(shù),都可以有一個(gè)屬性,該屬性指向一個(gè)對(duì)象。線程的劃分尺度小于進(jìn)程,使得多線程程序的并發(fā)性高。但是線程不能夠獨(dú)立執(zhí)行,必須依存在應(yīng)用程序中,由應(yīng)用程序提供多個(gè)線程執(zhí)行控制。 原文鏈接:征服前端面試,僅供學(xué)習(xí)使用前端知識(shí)集錦2 1. JavaScript 1.1 原型 我們創(chuàng)建的每一個(gè)函數(shù),都可以有一個(gè)prototype...

    Paul_King 評(píng)論0 收藏0
  • 前端知識(shí)集錦1

    摘要:原文鏈接征服前端面試,僅供學(xué)習(xí)使用前端知識(shí)集錦原型我們創(chuàng)建的每一個(gè)函數(shù),都可以有一個(gè)屬性,該屬性指向一個(gè)對(duì)象。線程的劃分尺度小于進(jìn)程,使得多線程程序的并發(fā)性高。但是線程不能夠獨(dú)立執(zhí)行,必須依存在應(yīng)用程序中,由應(yīng)用程序提供多個(gè)線程執(zhí)行控制。 原文鏈接:征服前端面試,僅供學(xué)習(xí)使用前端知識(shí)集錦2 1. JavaScript 1.1 原型 我們創(chuàng)建的每一個(gè)函數(shù),都可以有一個(gè)prototype...

    spademan 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<