07.消除过期对象的引用
前言
《Effective Java》中文第三版,是一本关于Java基础的书,这本书不止一次有人推荐我看。其中包括我很喜欢的博客园博主五月的仓颉,他曾在自己的博文《给Java程序猿们推荐一些值得一看的好书》中也推荐过。加深自己的记忆,同时向优秀的人看齐,决定在看完每一章之后,都写一篇随笔。如果有写的不对的地方、表述的不清楚的地方、或者其他建议,希望您能够留言指正,谢谢。
是什么
过期对象的引用:指的是永远不会再被解除的引用。为什么会出现这样的情况,这是因为我们的栈在显示增长,然后再收缩,那么从栈中弹出来的对象将不会被当做垃圾回收,即使使用的栈的程序不再引用这些对象,它们也不会被回收。因为,栈内部维护着对这些对象的过期引用。
没有消除过期对象实例,代码如下:
/**
* @author gongguowei01@gmail.com
* @since 2020-01-19
*/
public class Stack {
public Object[] elements;
public int size = 0;
private static final int DEFAULT_VALUE = 16;
public Stack() {
elements = new Object[DEFAULT_VALUE];
}
public void push(Object e) {
ensureCapacity();
elements[size++] = e;
}
public Object pop() {
if (0 == size) {
throw new EmptyStackException();
}
return elements[--size];
}
public void ensureCapacity() {
if (elements.length == size) {
elements = Arrays.copyOf(elements, 2 * size + 1);
}
}
}
上方代码测试实例如下
/**
* @author gongguowei01@gmail.com
* @since 2020-01-19
*/
public class Test {
public static void main(String[] args) {
Stack stack = new Stack();
stack.push("1");
stack.push("2");
stack.pop();
stack.push("3");
}
}
运行结果如下
当我们调用pop()方法时,size变为1,但是elements数组中还存在过期对象“1”的引用。
消除过期对象的引用,代码实例如下
/**
* @author gongguowei01@gmail.com
* @since 2020-01-19
*/
public class Stack02 {
public Object[] elements;
public int size = 0;
private static final int DEFAULT_VALUE = 16;
public Stack02() {
elements = new Object[DEFAULT_VALUE];
}
public void push(Object e) {
ensureCapacity();
elements[size++] = e;
}
public Object pop() {
if (0 == size) {
throw new EmptyStackException();
}
Object result = elements[--size];
//消除过期对象引用
elements[size] = null;
return result;
}
public void ensureCapacity() {
if (elements.length == size) {
elements = Arrays.copyOf(elements, 2 * size + 1);
}
}
}
哪里用
在有可能出现内存泄露的场景
- 缓存
- 自己管理内存的场景
- 监听器和其他回调
总结
不消除过期对象的引用,将会引起内存泄露,内存泄漏通常不会表现为明显的故障,所以它们可能会在系统中保持多年。 通常仅在仔细的代码检查或借助堆分析器(heap profiler)的调试工具才会被发现。 因此,学习如何预见这些问题,并防止这些问题发生,是非常值得的。