相對於 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還有像是監聽器 (Listener) 及 callback,開發者因需求註冊監聽器及 callback,在不需使用後,忘記將其取消註冊,同樣也會造成 memory leak。其實 memory leak 不常被發現,大多需要使用 Heap Profiler 等工具才能發現。
https://www.baeldung.com/java-weakhashmap
https://droidyue.com/blog/2018/07/23/a-briefing-looking-at-weakhashmap/
轉載請註明原文網址 https://cookieandcoketw.blogspot.com/2020/06/effective-java-7-object-reference.html
沒有留言:
張貼留言