Joshua Bloch的《effective java》中的item 6,给出了一个模拟栈的例子。
其中在出栈代码段为:
public Object pop()
{
if (size == 0)
{
throw new EmptyStackException();
}
return elements[--size];
}
以上代码可以看出在出栈以后,大于等于size的对象元素,依然没有被垃圾回收器回收,书中改进后的代码段为:
public Object pop()
{
if (size == 0)
{
throw new EmptyStackException();
}
Object result = elements[--size];
elements[size] = null;
return result;
}
这样对弹出的对象元素赋值为null,清空过期引用的目的,避免了内存泄漏。
书中还介绍了内存泄漏的另外两个来源是1.缓存,2.监听器和其他回调。对应解决办法是使用WeakHashMap.
1.缓存:
我们现在实现一个这样的缓存,只要在缓存之外存在对某个项的键的引用,该项就有意义,如果缓存之外没有最这个项的键的引用了,我们就删除该项。此时使用WeakHashMap来代表缓存就能实现这个目的。WeakHashMap的某一项<K,V>的生命周期就是由该键K的外部引用而不是由值V(是不是null)来决定的。
当缓存项的生命周期是否有意义的标准变得模糊时,比如随着时间的推移导致的缓存中的项变得越来越没有价值,那么清除工作可以交给后台线程来完成。更复杂的情况则考虑java.lang.ref.
2.针对API,客户对API注册回调,但是没有取消注册造成的回调积聚。书中介绍了使用只保存回调的弱引用,比如将回调保存成WeakHashMap的键(此处依然理解不够深刻,标记)。