Effective Java Item7 移除不需要的物件引用
整理Effective Java書中Item 7: Eliminate obsolete object references心得筆記
主旨
由於Java有GC的機制,很多時候開發者不會考慮到記憶體管理或著覺得不需要考慮,這是錯誤的觀念,如果忽略可能導致潛在memory leak問題,必須重視。
點出問題
- array
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
}
這個蠻經典的範例在ArrayList原始碼中,調用remove後,關鍵就在elementData[--size] = null;
這行進行釋放,如果沒有這行GC不會知道要處理。
- caches
我們常會將很多不同的資料放到cache裡面,但過些時間後又沒有定期清理,很容易就把資料忘在裡面,即使已經不在使用了。如果是這總狀況可以使用WeakHashMap
來當cache的map。存在這個map的值如果已經沒有任何外部引用將自動被刪除。這裡的Weak指的就是弱引用,表示若沒有任何引用當GC執行後就馬上就被清理。可以跑跑看下面範例。
public class Item7 {
public static void main(String[] args) {
Map<Key, Value> cache = new WeakHashMap<>();
Key key1 = new Key("Alice");
Value value1 = new Value("apple");
Key key2 = new Key("Bob");
Value value2 = new Value("orange");
cache.put(key1, value1);
cache.put(key2, value2);
key1 = null;
System.gc();
for (Map.Entry<Key, Value> entry : cache.entrySet()) {
System.out.println("Key : " + entry.getKey() + " Value : " + entry.getValue());
}
}
static class Key {
private String key;
public Key(final String key) {
this.key = key;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Key [key=");
builder.append(key);
builder.append("]");
return builder.toString();
}
}
static class Value {
private String value;
public Value(final String value) {
this.value = value;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Value [value=");
builder.append(value);
builder.append("]");
return builder.toString();
}
}
}
- listeners and other callbacks
假如你在總公司提供了一個簡單的推送API服務,集團會員登入上線會自動註冊你的服務,會員就可以收到總公司的推送消息。一開始沒什麼問題,使用時間久了後發現server負擔越來越大導致OOM,一時也找不出原因只能先靠重啟暫時解決問題,這樣類似的問題困擾著很多開發者又不得其門而入。這個例子其實很多會員下線了以後服務根本不知道,也沒有進行取消註冊服務,導致最後服務每次都要一直大量推送資料給沒有在線的會員。
小結
記憶體洩漏的問題通常不會表現得很明顯,都會在某個壓力峰值或著某個特別的操作爆發,它們可能在系統裡面是一顆多年的毒瘤,目前的解決方法不外乎是仔細的進行code review以及小規模的重構系統,或著透過分析工具來檢測系統。
參考延伸閱讀:
Read other posts