《EffectiveJava》读后感(第2章创建和销毁对象 第6条)

消除过期的对象引用

在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];
} p
ublic void push(Object e) {
ensureCapacity();
  
elements[size++] = e;
} p
ublic Object pop() {
if (size == 0)
throw new EmptyStackException();
return elements[--size];
} /
**
* Ensure space for at least one more element, roughly
* doubling the capacity each time the array needs to grow.
*/
private void ensureCapacity() {
if (elements.length == size)
elements = Arrays.copyOf(elements, 2 * size + 1);
}
}

这里并没有明显的错误,并且能够通过每一条测试,但是这个程序中隐藏着一个问题。这段代码存在“内存泄漏”,随着程序的运行并且没有做任何处理的话甚至会出现OOM导致的程序失败的问题。这里的原因时在对象使用过后,垃圾回收不能回收使用过的对象,原因是栈的内部维护着这些对象的过期引用。

这一类的问题处理很简单:一旦对象引用过期,只需要清空这些引用就可以了。

public Object pop() {
if (size == 0)
throw new EmptyStackException();
Object result = elements[--size];
elements[size] = null; // Eliminate obsolete reference
return result;
}

但是也不必对每一个产生的对象都用清空的办法,清空对象的引用应该是一种例外,而不是一种规范行为。消除过期引用的最好办法是结束变量的生命周期。

简而言之,Stack类自己管理内存,存储池包含了elements数组(对象引用单元,而不是对象本身)的元素。数组活动区域中的元素是已分配的,而数组之外的元素是自由的。但是垃圾回收器不知道这一点。解决办法就是程序员手工的清楚非活动的元素。一般而言,只要类自己管理内存,程序员就要警惕内训泄露的问题。

内存泄漏的另一个常见来源是缓存,因为容易遗忘从而导致OOM的问题。解决办法之一就是使用WeakHashMap,但是要注意只有该键由外部引用而不是由值决定的时候WeakHashMap才有用处。解决之二是开启一个后台线程定时清理掉没用的项。解决之三是LinkedHashMap类利用它的removeEldestEntry方法可以轻易的实现后一种方案。对于更复杂的场景,必须直接使用java.lang.ref。

内存泄漏的第三个常见来源是监听器和其他回调。实现了一个API,客户端完成API中的注册回调,却没有显示的取消注册。解决办法:只将他们保存为WeakHashMap的键。

由于内存泄漏通常需要长时间的累积才会爆发,所以可以借助Heap工具进行剖析防规于未然。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值