消除过期对象的引用

为什么要手动消除过期对象的引用

虽然JDK自带垃圾回收机制会自动回收不再使用的对象,但是JDK的垃圾回收机制并没有那么智能,仍会存在“内存泄漏”问题,例如下面的例子:

import java.util.Arrays;
import java.util.EmptyStackException;

public class Stack {
	private Object[] elements;
	private int size = 0;
	private static final int DEFAULT_INITIAL_CAPACITY = 8;
	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();
		Object result = elements[--size];
		//elements[size] = null;
		return result;
		
	}

	private void ensureCapacity() {
		if(elements.length == size) {
			elements = Arrays.copyOf(elements, 2 * size +1);
		}
		
	}
	
	@Override
	public String toString() {
		return "Stack [elements=" + Arrays.toString(elements) + ", size=" + size + "]";
	}

	public static void main(String[] args) {
		Stack s = new Stack();
		s.push("hua");
		s.push(new Object());
		s.push(90);
		System.out.println(s);
		System.out.println(s.pop());
		System.out.println(s);
		
		
		
	}

}

测试结果如下:

在这里插入图片描述
从测试结果中我们可以看到虽然我们已经弹出了90,但是在栈中并没有删除,仍然存在,在之后的一些操作仍然可以被使用,这样就会造成误操作。
  上面的例子我们看到了存在的问题,程序中发生了内存泄漏,可以看出一个栈先增长再收缩,那么从栈中弹出来的对象就不会被当做垃圾回收,即使使用栈的程序不再引用这些对象,他们也不会被回收。这是因为栈内部维护者对这些过期对象的引用。
  在支持垃圾回收的语言中,内存泄漏时很隐蔽的(称这类内存泄漏为“无意识的对象保持”)。如果一个对象引用被无意识的保留了起来,那么垃圾回收机制不仅不会处理这个对象,而且也不会处理被这个对象所引用的所有其他对象。
  这类问题修复的方法很简单:一旦对象引用已经过期,只需要清空这些引用即可。  
修改方法,只需要修改pop()中的代码:

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

测试结果如下:
在这里插入图片描述
  清空过期引用的另一个好处是,如果它们以后又被错误地解除引用,程序就会立即抛出NullPointerException异常,而不是悄悄地错误运行下去。
尽快地检测出程序中的错误总是有益的。消除过期引用最好的方法是让包含该引用的变量结束其生命周期。
  那么什么时候应该清空引?
  一个简单的规则:一旦数组元素变成了非活动部分的一部分,程序员就手工清空这些数组元素。
  一般而言,只要类是自己管理内存,程序员就应该警惕内存泄漏问题。一旦元素被释放掉,则该元素中包含的任何对象引用都应该被清空。
  内存泄漏的另一个常见来源是缓存。一旦你把对象引用放到缓存中,它就很容易被遗忘掉,从而使得它不再有用之后很长一段时间内仍然留在缓存中。
  内存泄漏的第三个常见来源是监听器和其他回调。
造成内存泄漏的原因是什么?
很多时候内存泄漏都是“人们无意识的对象引用”造成的。

List<String> list = new ArrayList<>();
String s = "testString";
list.add(s);
s  = null;

list依然持有对str的引用,所以创建str时所开辟的内存空间是不会被回收的,这就是一个典型的“无意识的内存引用”。
为了防止这些“无意识的内存引用”,我们应该了解对象相互引用的时候是存在怎样的依赖关系的。

6、对象间相互依赖是怎样的

Object obj1 = new Object();
Object obj2 = obj1;
Object obj3 = obj2;

所以说下面这段代码,new 出来的那片内存空间是不会被回收的,因为obj2和obj3还在持有这片内存的引用。

Object obj1 = new Object();
Object obj2 = obj1;
Object obj3 = obj2;
object1 = null;

如何处理内存泄漏问题
对于长生命周期的变量,我们可以进行手动回收,或者使用弱引用。
总结:对于使用数组、集合元素的对象引用需要手动回收

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值