public class Stack {
// 底层使用的是数组 没毛病
private Object[] elements;
// size作为指针 没毛病
private int size = 0;
// 默认容量 没毛病
private static final int DEFAULT_INITIAL_CAPACITY = 16;
public Stack() {
elements = new Object[DEFAULT_INITIAL_CAPACITY];
}
// 扩容机制
private void ensureCapacity() {
if (elements.length == size) {
elements = Arrays.copyOf(elements, 2 * size + 1);
}
}
// 入栈
public void push(Object e) {
ensureCapacity();
elements[size++] = e;
}
// 出栈 (注意这个方法!!!)
public Object pop() {
if (size == 0) {
throw new EmptyStackException();
}
return elements[--size];
}
}
这里内存泄漏的风险点是从栈中弹出的对象不会被垃圾回收器回收,是因为栈虽然不再使用这些对象,但内部却维护着他们的过期引用。所谓过期引用,是指永远也不会再被解除的引用,一个解决方案是,对该位置置NULL
public Object pop() {
if (size == 0) {
throw new EmptyStackException();
}
Object rs = elements[--size];
elements[size] = null
return rs
}
那么是否来说,针对这些集合,我们都采用此方案呢,当然不合适,如果这样,不仅仅会使代码变脏,也不一定适用于所有场景。
一般来说,只要是类自己管理内存,就应该警惕内存泄漏问题。
扩展:
静态集合类,如HashMap、LinkedList等等。如果这些容器为静态的,那么它们的生命周期与程序一致,则容器中的对象在程序结束之前将不能被释放,从而造成内存泄漏。简单而言,长生命周期的对象持有短生命周期对象的引用,尽管短生命周期的对象不再使用,但是因为长生命周期对象持有它的引用而导致不能被回收。
解决办法是最好不使用静态的集合类,如果使用的话,在不需要时要将其赋值为null。如果是不使用的key,调用remove即可,map和list的remove方法不存在栈的这个问题,直接清除了对象引用,那么不存在强引用,该值自然也会被回收。
无需过分在意此类场景,低概率事件,遇见时考虑可能时这种情况。
缓存当没有对象引用时,往往也会放在内存中,等待过期策略去清理,书中提到的weakHashMap,在对其调用get,put等方法时,就会过滤一遍是否存在弱引用,存在则移除,会出现两个问题,
1.遍历会得到不同结果
2.如果没有引用就清楚,而缓存通常是在某个时间段被高频使用,而不是不间断都有引用。(待实践确认)
所以我觉得用weakHashMap代替不太好,至于3则适用weakHashMap
如果你实现了一个API,客户端在这个KPI中注册回调,但是没有显式的取消注册,那么在你没有对其作特殊处理的情况下,他们就会不断堆积,从而导致泄漏。解决方法和上面的例子一样,将它们保存为WeakHashMap的键即可。
原文:https://www.cnblogs.com/kunkka-0717/p/14426510.html