Q: Java內存泄漏是種什么樣的體驗?

Java的內存泄漏

查看代碼:

public class Stack {
    private Object[] elements;
    private int size = 0;
    private static final int DEFAULT_INITAL_CAPACITY = 16;

    public Stack() {
        elements = new Object[DEFAULT_INITAL_CAPACITY];
    }

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

    public Object pop() {
        if (size == 0)
            throw new EmptyStackException();
        return elements[--size];
    }

    private void ensureCapacity() {
        if (elements.length == size) {
            elements = Arrays.copyOf(elements, 2*size+1);
        }
    }
}

這段程序中并沒有很明顯的錯誤。但是這個程序中隱藏著一個問題。不嚴格的講,就是“內存泄漏”,隨著垃圾回收器活動的增加,或者由于內存占用的不斷增加,程序性能的降低會表現(xiàn)出來。在極端情況下,這種內存泄漏會導致磁盤交換,甚至導致OutOfMemoryError。

如果一個棧先增長,然后再收縮,那么,從棧中彈出的對象不會被當作垃圾回收,即使使用棧的程序不再引用這些對象,它們也不會被回收。這是因為,棧內部維護著對這些對象的過期引用。

過期引用:是指永遠不會被解除的引用

在上面的例子中,凡是在elements數(shù)組的活動部分之外的任何引用都是過期的。

在Java這樣的支持垃圾回收的語言中,內存泄漏是隱藏的。如果一個對象引用被無意識地保留起來了,那么垃圾回收機制不僅不會處理這個對象,而且也不會處理這個對象所引用的所有其他對象。

這里我們會對彈出的元素做一些簡單的處理:如下

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

只要類是自己管理內存,程序員就應該警惕內存泄漏問題。一旦元素被釋放掉,則該元素中包含的任何對象引用都應該被清空。

內存泄漏的另一個常見來源是緩存,一旦把對象引用放到緩存中,它就很容易被遺忘掉,從而使得它不再有用之后很長一段時間內仍然留在緩存內。

如果想要實現(xiàn)這樣的一個緩存:只要在緩存之外存在對某個項的健的引用,該項就有意義,那么就可以用WeakHashMap代表緩存;當緩存中的項過期之后,它們就會被自動刪除。只有當所要的緩存項的生命周期是由該健的外部引用而不是由值決定時,WeakHashMap才有用處

內存泄漏的另一個常見來源是監(jiān)聽器和其他回調,如果實現(xiàn)了一個API,客戶端在這個API中注冊回調,卻沒有顯式的取消注冊,那么除非采取某些動作,否則他們會聚集。確?;卣{立即被當做垃圾回收的最佳方法是只保存它們的弱引用。

內存泄漏往往是一個不明顯的Bug。BeCareful!!!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容