《Effective Java 中文版 第2版》学习笔记 第6条:消除过期的对象引用
Posted 王景迁
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《Effective Java 中文版 第2版》学习笔记 第6条:消除过期的对象引用相关的知识,希望对你有一定的参考价值。
内存泄漏的第一个常见来源是存在过期引用。
1 import java.util.Arrays; 2 import java.util.EmptyStackException; 3 4 public class Stack { 5 6 private Object[] elements; 7 private int size = 0; 8 private static final int DEFAULT_INITIAL_CAPACITY = 16; 9 10 public Stack() { 11 elements = new Object[DEFAULT_INITIAL_CAPACITY]; 12 } 13 14 private void ensureCapacity() { 15 if (elements.length == size) { 16 elements = Arrays.copyOf(elements, 2 * size + 1); 17 } 18 } 19 20 public void push(Object e) { 21 ensureCapacity(); 22 elements[size++] = e; 23 } 24 25 public Object pop() { 26 if (size == 0) { 27 throw new EmptyStackException(); 28 } 29 30 return elements[--size]; 31 } 32 33 }
如果一个栈先是增长,然后再收缩,从栈中弹出来的对象不会被当作垃圾回收,即使使用栈的程序不再引用这些对象,它们也不会被回收。因为栈内部维护着对这些对象的过期引用(obsolete reference)。过期引用指永远也不会再被解除的引用。在本例中,在elements数组的“活动部分(active portion)”之外的任何引用都是过期的。活动部分指elements中下标小于size的那些元素。
如果一个对象引用被无意识地保留了,垃圾回收机制不仅不会回收这个对象,而且不会回收被这个对象所引用的所有其他对象。解决方法:一旦对象引用已经过期,只需清空这些引用即可。在本例中,只要一个元素被弹出栈,指向它的引用就过期了。修改如下:
1 public Object pop() { 2 if (size == 0) { 3 throw new EmptyStackException(); 4 } 5 6 Object result = elements[--size]; 7 elements[size] = null; // 清空引用 8 9 return result; 10 }
清空过期引用的另一个好处是,如果它们以后又被错误地解除引用,程序会立即抛出NullPointerException异常,而不是悄悄地错误运行下去。尽快地检测出程序中的错误总是有益的。消除过期引用最好的方法是让包含该引用的变量结束其生命周期。如果在最紧凑的作用域范围内定义每一个变量(见第45条),这种情形会自然而然地发生。
只要类是自己管理内存,程序员就应该警惕内存泄漏问题。一旦元素被释放掉,该元素中包含的任何对象引用都应该被清空。
内存泄漏的第二个常见来源是缓存。
把对象引用放到缓存中,它就很容易被遗忘掉,从而使得它不再有用之后很长一段时间内仍然留在缓存中。用WeakHashMap代表缓存时,当缓存中的项过期之后,它们会被自动地删除。只有当缓存项的生命周期是由该键的外部引用而不是由值决定时,WeakHashMap才起作用。
随着时间的推移,缓存项会变得越来越没有价值,缓存应该时不时地清除掉没用的项。可以由一个后台线程(可能是Timer或者ScheduledThreadPoolExecutor)来完成,或者在给缓存添加新条目时进行清理。LinkedHashMap类可以通过它的removeEldestEntry方法来实现后者。对于更加复杂的缓存,必须直接使用java.lang.ref。
内存泄漏的第三个常见来源是监听器和其他回调。
如果客户端在自己实现的API中注册回调,却没有显式地取消注册,那么除非自己采取某些动作,否则它们就会积聚。确保回调立即被当作垃圾回收的最佳方法是只保存它们的弱引用(weak reference),例如,只将它们保存为WeakHashMap中的键。
往往只有通过仔细检查代码,或者借助于Heap剖析工具(Heap Profiler)才能发现内存泄露问题。
参考资料
《Effective Java 中文版 第2版》 P21-23
以上是关于《Effective Java 中文版 第2版》学习笔记 第6条:消除过期的对象引用的主要内容,如果未能解决你的问题,请参考以下文章
《Effective Java 中文版 第2版》学习笔记 第6条:消除过期的对象引用
Effective Java中文版(第2版) PDF分享下载