6. 【创建和销毁对象】消除过期的对象引用
来源:互联网 发布:linux dhcp设置dns 编辑:程序博客网 时间:2024/06/07 17:48
本文是《Effective Java》读书笔记第6条,其中内容可能会结合实际应用情况或参考其他资料进行补充或调整。
我们都知道,Java语言的优势之一就是具有垃圾回收技能,这一点尤其是对一些从C或C++语言转过来的程序猿来说感觉尤其方便,仿佛使用Java就不需要考虑内存管理的事情了,真的是这样吗?
无意识的对象保持
先看下边的代码,这段代码用于实现一个简单的栈:
public class MyStack { private Object[] elements; private int size = 0; private static final int DEFAULT_INITIAL_CAPACITY = 16; public MyStack() { elements = new Object[DEFAULT_INITIAL_CAPACITY]; } public void ensureCapacity() { if (elements.length == size) { elements = Arrays.copyOf(elements, 2 * size + 1); } } public void push(Object o) { ensureCapacity(); elements[size++] = o; } public Object pop() { if (size == 0) { throw new EmptyStackException(); } return elements[--size]; }}
程序中并没有明显的错误,测试可用,但其实程序中存在内存泄漏。
当栈的长度增长由收缩后,那么从栈中pop
出的对象不会被当做垃圾回收,而实际上根据栈的使用特点,这些对象在使用之后就不会再被引用了。
这是因为栈内部维持着对这些对象的过期引用(指永远不会再被解除的引用)。
有时候内存泄漏是很隐蔽的,假设过期引用指向的对象内还含有更多的过期引用,就会形成链状或树状引用,这些引用指向的对象同样不会被垃圾回收,从而影响性能。
这类问题的修复方法很简单:一旦对象引用过期,只需清空这些引用即可。不多解释,下边代码中找吧:
public Object pop() { if (size == 0) { throw new EmptyStackException(); } Object result = elements[--size]; elements[size] = null; // 清除引用 return result; }
清空过期引用还有个好处,就是如果它以后又被错误地解除引用,程序就会立即抛出空指针异常,而不是悄悄地错误运行下去。尽快得检查出程序中的错误总是有益的。
清除对象引用应该是一种例外,而不是一种规范行为。以上内容并不是让您一旦不再使用某个对象,就立马清除其引用,这样做既没有必要也不是我们所期望的。最好的方法是让包含该引用的变量结束其生命周期。如果您是在最紧凑的作用域范围内定义每个变量,这种情况就会自然而然地发生。那MyStack类的哪些特性导致了它易于内存泄漏呢?问题在于MyStack类自己管理内存,也就是elements数组,这种情况下就需要额外关注。
缓存
内存泄漏的另一个常见来源是缓存。一旦您把对象引用放到缓存中,它就很容易被遗忘掉,从而使得它不再有用但仍然留在缓存中。
如果您正要实现这样的缓存,可以用WeakHashMap代表缓存,当缓存中的项过期后,它们就会自动删除。若要使某缓存项有意义,只要在缓存之外保存对这个项的键的引用即可。
更为常见的情形则是,缓存项的生命周期是否有意义并不是很确定,随着时间的推移,其中的项会变得原来越没有价值。这时候利用LinkedHashMap类的removeEldestEntry
方法可以很容易实现。对于更复杂的缓存,必须直接使用java.lang.ref。
java.lang.ref包提供了与Java垃圾回收器密切相关的引用类,包括我们日常使用的强类型,刚才提到的弱引用,以及能够根据JVM的内存状况“智能”处理引用清理的软引用等,具体请见深入探讨java.lang.ref。
监听器及回调
内存泄漏的第三个常见来源是监听器和其他回调。如果您实现了一个API,客户端在这个API中注册回调,却没有显式地取消注册,那么除非您采取某些动作,否则它们就会积累。确保回调立即被当成垃圾回收的最佳方法是只保存它们的弱引用,例如,只将它们保存成WeakHashMap中的键。
最后
由于内存泄漏通常不会有明显的错误或异常,所以可以在一个系统中存在多年。往往只有通过仔细的代码检查,或是借助Heap剖析工具才能发现内存泄漏问题。因此,如果能够在内存泄漏发生之前就知道如何预测此类问题,并阻止它们发生,那就再好不过了。
- 6. 【创建和销毁对象】消除过期的对象引用
- 第6条 创建和销毁对象——消除过期的对象引用
- 创建和销毁对象 第六条:消除过期的对象引用
- Effective Jave 创建和销毁对象 6.消除过期的对象应用
- 创建和销毁对象(3)(4)——避免创建不必要的对象,消除过期对象
- 6.消除过期对象的引用
- 消除过期的对象引用
- 消除过期的对象引用
- 消除过期的对象引用
- 消除过期的对象引用
- 消除过期的对象引用。
- 学习effective java-6创建和销毁对象之消除过时的对象引用
- 消除过期的对象引用的理解
- JAVA消除过期的对象引用
- 06、消除过期的对象引用
- 数组中消除过期的对象引用
- 006-消除过期的对象引用
- 6、消除过期的对象引用
- Ajax实战总结——用原生JavaScript代码封装自己的Ajax核心对象
- Angular的Directive,以及copmile和link方法
- java微信公众平台分享朋友圈
- Spring/Hibernate/Proxool集成
- 数据结构-二叉树
- 6. 【创建和销毁对象】消除过期的对象引用
- java微信公众号开发怎样进行本地联调
- android模拟器 Genymotion 安装破解版
- ightoj 1011 状态压缩dp
- Android Fragment 真正的完全解析(上)
- 系统学习bootstrap——day1
- Hadoop—FS Shell
- Android Fragment 真正的完全解析(下)
- 欢迎使用CSDN-markdown编辑器