前言
你能看出以下代码哪里内存泄漏吗?
// Can you spot the "memory leak"? |
分析与解答
答案是:
pop() 方法存在内存泄漏。
内存泄漏可以称为 “ 无意识的对象保持(unintentional object retention)”。
在 pop() 方法中从栈中弹出来的对象将不会被当做垃圾回收。栈内部维护着对这些对象的过期引用(obsolete reference)。所谓的过期引用,是指永远也不会再被解除的引用。凡是在 elements 数组的 “活动部分”(active portion)之外的任何引用都是过期的。活动部分是指 elements 中下标小于 size 的那些元素。
解决方法:上述述例子中的 Stack 类而言,只要一个单元被弹出栈,指向它的引用就过期了。一旦数组元素变成了非活动部分的一部分,就手工清空这些数组元素。修改后的 pop() 方法如下:
public Object pop() { |
清空对象引用应该是一种例外,而不是一种规范行为。消除过期引用最好的方法是让包含该引用的变量结束其生命周期。
延伸阅读
length、size()、length() 的区别:
- 数组的长度(length):数组能容纳元素个数的值
- 泛型集合的大小(size()):泛型中元素的个数
- 字符串的长度(length()):字符的个数
前缀递减和后缀递增:
- 前缀递减,”–” 操作符位于变量或表达式前,先执行运算,再生成值。如上例中
elements[--size]
,size 大小先减 1,所以Object result = elements[--size];
中 result 元素下标为 size=size-1。 - 后缀递增,”++” 操作符位于变量或表达式后,先生成值,再执行运算。如上例中
elements[size++] = e;
,元素下标为 size,再执行运算 size=size+1。
Arrays.copyOf() 方法:
- a copy of the original array, truncated or padded with nulls to obtain the specified length(原始数组的副本,缩短或填补 null 来获取指定的长度)。
- 作用:如果数组元素的个数等于数组的长度,新建副本数组,将长度扩大为两倍加一,将数组副本赋值给 elements。