第六条 消除过期的引用
2016-06-01 15:57
169 查看
java 中有自动垃圾回收机制,如果以为不用自己手动处理,jvm可以全局处理,那就有点错了
例如
public class Stack {
private Object[] elements;
private int size = 0;
private static final int DEFAULT = 16;
public Stack(){
elements = new Object[DEFAULT];
}
public void push(Object o){
ensure();
elements[size++] = o;
}
public Object pop(){
if(size == 0){
throw new EmptyStackException();
}
return elements[--size];
}
private void ensure(){
if(elements.length == size){
elements = Arrays.copyOf(elements, size *2 +1);
}
}
}
joshua大神的例子
这段代码看起来没问题,但有个小问题:内存泄漏。随着数组笔挺变大,程序性能会下降,应为 数组 elements 不停增大,调用 pop()功能,数据仍然存在数组中,极端情况,数组会造成内存泄漏 oom。 一个类似的例子时集合,我们用到集合后,有些小伙伴会在不用时置空,以为完事,其实置空前应该先 clean()一下,清除集合里面的元素,然后吧集合对象置空。
同理,上述数组中,可以修改 pop()方法,在弹出数组对象时,把数组里面的引用置空
public Object pop(){
if(size == 0){
throw new EmptyStackException();
}
Object obj = elements[--size];
elements[size] = null;
return obj;
}
清除过期引用的另一个好处是一旦被错误引用,程序会立刻抛出异常,而不是悄悄的继续错误的运行下去。
effective java 作者 joshua大神明确说:清空对象引用应该是一种例外,而不是一种规范行为。
是不是觉得前后矛盾? 这么说主要是因为 对于每一个程序对象,一旦不用就清空,很容易把代码弄混乱,消除过期引用的最好方法时控制其生命周期来结束引用,而不是到处置空。一般而言,只要是类自己管理内存,我们就该警惕内存泄漏了,就像是上述代码一样。
另一种是缓存。把对象引用放入缓存,很容易就被遗忘。对于这种,常见的解决方案是弱引用。缓存中的内容过期后,自动被删除。或者采用类似 LinkedHashMap 的容器,在增加新条目的同时会自动清理以前的条目,对于更复杂的封装好的缓存工具,可以使用 java.lang.ref。
第三种常见的是监听器和其他回调。如果只注册回调,没有对应的取消注册,那么就会越聚越多,造成内存泄漏。Android中常见的就是广播注册,没有在activity结束的生命周期里取消注册。
内存泄漏是一个大的模块,只有在平常中积累,才能慢慢提高。
例如
public class Stack {
private Object[] elements;
private int size = 0;
private static final int DEFAULT = 16;
public Stack(){
elements = new Object[DEFAULT];
}
public void push(Object o){
ensure();
elements[size++] = o;
}
public Object pop(){
if(size == 0){
throw new EmptyStackException();
}
return elements[--size];
}
private void ensure(){
if(elements.length == size){
elements = Arrays.copyOf(elements, size *2 +1);
}
}
}
joshua大神的例子
这段代码看起来没问题,但有个小问题:内存泄漏。随着数组笔挺变大,程序性能会下降,应为 数组 elements 不停增大,调用 pop()功能,数据仍然存在数组中,极端情况,数组会造成内存泄漏 oom。 一个类似的例子时集合,我们用到集合后,有些小伙伴会在不用时置空,以为完事,其实置空前应该先 clean()一下,清除集合里面的元素,然后吧集合对象置空。
同理,上述数组中,可以修改 pop()方法,在弹出数组对象时,把数组里面的引用置空
public Object pop(){
if(size == 0){
throw new EmptyStackException();
}
Object obj = elements[--size];
elements[size] = null;
return obj;
}
清除过期引用的另一个好处是一旦被错误引用,程序会立刻抛出异常,而不是悄悄的继续错误的运行下去。
effective java 作者 joshua大神明确说:清空对象引用应该是一种例外,而不是一种规范行为。
是不是觉得前后矛盾? 这么说主要是因为 对于每一个程序对象,一旦不用就清空,很容易把代码弄混乱,消除过期引用的最好方法时控制其生命周期来结束引用,而不是到处置空。一般而言,只要是类自己管理内存,我们就该警惕内存泄漏了,就像是上述代码一样。
另一种是缓存。把对象引用放入缓存,很容易就被遗忘。对于这种,常见的解决方案是弱引用。缓存中的内容过期后,自动被删除。或者采用类似 LinkedHashMap 的容器,在增加新条目的同时会自动清理以前的条目,对于更复杂的封装好的缓存工具,可以使用 java.lang.ref。
第三种常见的是监听器和其他回调。如果只注册回调,没有对应的取消注册,那么就会越聚越多,造成内存泄漏。Android中常见的就是广播注册,没有在activity结束的生命周期里取消注册。
内存泄漏是一个大的模块,只有在平常中积累,才能慢慢提高。
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树