effective java
读书笔记 仅供参考
Java 一个很重要的特色就是垃圾回收,但是它也不是万能的,有兴趣的可以阅读《深入理解 Java 虚拟机》
一段经典的内存泄漏案例
public class Stack {
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
public Stack() {
elements = new Object[DEFAULT_INITIAL_CAPACITY ];
}
public void push(Object e) {
ensureCapacity();
elements[size++] = e;
}
pubic Object pop() {
if(size == 0) {
throw new EmptyStackException();
}
return element[--size];
}
private void ensureCapacity() {
if(elements.length == size) {
elements = Arrays.copyOf(elements, 2 * size + 1);
}
}
}
上面这段程序写了一个栈的出栈和入栈,表面上没有问题,但是在长时间运行后,会有出现内存泄漏的可能。
主要问题就在 pop() 方法上,在出栈时,只是将 size 减少,但是没有将引用消除。Java 的引用有四种:强引用,弱引用,软引用和虚引用(关于引用)。上述的就是采用强引用(在 Java 的编写中基本都是使用强引用,个人而言),所以在使用强引用时,即时内存空间不足,垃圾回收器也不会清理这些对象,而是抛出 OutOfMemoryError。
上面所说的就是过期引用:永远不会被解除的引用。
修复方法
pubic Object pop() {
if(size == 0) {
throw new EmptyStackException();
}
Object result = element[--size];
element[size] = null;
return result;
}
这样做的另一个好处:如果以后被错误的引用,会抛出 NPE 异常。
消除过期引用最好的方法时在最紧凑的作用域范围内定义每一个变量
内存泄漏第一来源
就是上面所说的过期引用,只要是自己管理内存,就应该警惕内存泄漏问题。
内存泄漏第二来源
缓存。
缓存应该时不时的清除掉没用的项,现在不少缓存工具都具有定时功能
内存泄漏第三来源
监听器和其他回调
确保回调立即被当中垃圾回收的最佳方法时只保存弱引用。