2020/06/30

[筆記] Effective Java #7 消除過期的物件引用

Effective Java 3rd 簡體中文版筆記 #7 消除過期的物件引用
相對於 C/C++ 來說,Java 會自動進行垃圾回收 (garbage collection),但並不表示開發者可以完全不管理 memory。如果物件已經過期,但沒有清除對該物件的引用,就算經過 JVM 多次的垃圾回收機制,物件依然會存在於 memory 中,這種現象稱作記憶體洩漏 (memory leak),嚴重時會出現 OutOfMemoryError
上述的問題,修正方法為當物件需要回收時,就清除對該物件的引用,清空物件引用應該是一種例外,垃圾回收機制可以回收絕大多數的過期物件,同時應讓變數的作用域最小化,縮短變數的生命週期。
// number should be method variable
public class Calculator {
    private Long number = 0;
    public Long cal() {
        ...
    }
}
public class Calculator {
    public Long cal() {
        Long number = ...
        return number;
    }
}
如果 class 自己處理 memory 的管理,開發者就應注意是否存在 memory leak 的問題。在 Stack 中,會管理一陣列,其中 pop() 內部調用 Vector 的 removeElementAt(int),在 removeElementAt 方法的最後,明確地將原本引用該物件的 array[index] 設定為 null,清除引用。
// java.lang.Stack source code
public synchronized E pop() {
    E       obj;
    int     len = size();
    obj = peek();
    removeElementAt(len - 1);
    return obj;
}
// java.util.Vector source code
public synchronized void removeElementAt(int index) {
    ...
    elementCount--;
    elementData[elementCount] = null; /* to let gc do its work */
}
Memory leak 另一個常見情境就是出現在 cache 中,放到 cache 的物件容易被遺忘,可以使用 WeakHashMap 來處理,或是由一 background thread 定期的去清除 cache,像是 ScheduledThreadPoolExecutor
WeakHashMap
https://www.baeldung.com/java-weakhashmap
https://droidyue.com/blog/2018/07/23/a-briefing-looking-at-weakhashmap/
還有像是監聽器 (Listener) 及 callback,開發者因需求註冊監聽器及 callback,在不需使用後,忘記將其取消註冊,同樣也會造成 memory leak。其實 memory leak 不常被發現,大多需要使用 Heap Profiler 等工具才能發現。

轉載請註明原文網址 https://cookieandcoketw.blogspot.com/2020/06/effective-java-7-object-reference.html

沒有留言:

張貼留言