2.6 移除过时的对象引用

如下代码(以下代码来自Effective 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];
	}

	public void push(Object e) {
		ensureCapacity();
		elements[size++] = e;
	}

	public 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);
	}
}

 

使用以上Stack类,如果循环放入100个不同的对象,接着循环弹出此100个对象,其私有属性elements数组仍然“引用”被弹出的100个对象,从而导致JVM不能回收此100对象所占用的内存,即内存泄露

 

注:

内存泄露:指对象占用的内存不能回收,甚至不断增大。导致JVM因内存不足频繁启动GC,进而降低程序运行性能。

内存溢出:指程序需要使用的内存,超出JVM所能使用的最大内存。内存溢出后JVM会终止并退出

 

为了解决此问题,可以进行如下修改,在弹出对象后,把elements对其的引用指向null。进而被弹出的对象可以被回收:

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

 

大多数情况下都不应该把变量显式的设置为null,以移除过时的引用。而是应该利用变量的作用域,在变量超出作用域范围后,利用GC自动移除所引用的对象(即JVM的GC机制)。变量的作用域应尽可能的小。

 

只有在编码者需要自行管理对象,即只有编码者知道创建的对象是否还需要使用的情况下,才需要显式的设置相关引用为null,以便GC能回收此对象。如上例对象被从elements移除后(这里移除只是修改了size变量的值),只有编程者知道Stack对象是否还需要使用被移除的对象,如果不需要使用,Stack对象不应该继续引用被移除的对象,所以需要显式的设置引用为null

 

以下情况需要考虑移除过时的引用:

1.类需要自行管理内存,如上Stack类自行管理elements数组。当对象被从elements移除后(这里移除只是修改了size变量的值),应该显式的设置对应的引用为null,以便GC。否则因为Stack仍然引用了被移除的对象,JVM不会对其进行GC

 

2.使用Cache,需要自行管理缓存的对象的移除

 

3.添加listener或callback对象,需要自行管理添加的listener或callback的移除

 

可以使用WeakHashMap管理添加的缓存对象或listener对象。WeakHashMap对添加的key对象使用“弱引用”,当除了WeakHashMap外,没有任何其他对象引用添加的key对象时,此key对象可以被GC。在GC时会从WeakHashMap里移除

 

需要注意的是WeakHashMap对添加的value对象仍然使用强引用。如果添加的value对象引用了key对象(或者其他对象应用了key对象),那么此key对象不会被GC。在添加value对象时,可以使用WeakReference进行封装。这样,如果仅有WeakHashMap对象引用value对象,那么value对象会被GC,进而key对象也被GC

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值