虽然当咱们用完对象后,java有垃圾回收机制进行回收,可是并无那么的智能,对于某些被引用的对象,就算咱们已经不在使用它了,可是java的回收机制是不会回收他们的,人们称之为“内存泄漏”。java
不少时候内存泄漏都是“人们无心识的内存引用”形成的,举个简单的例子:数组
List<String> list = new ArrayList<>(); String str = "testString"; list.add(str); str = null;
看似上面的str被回收了,可是,事实上建立str时所开辟的内存空间是不会被回收的,由于list依然持有对str的引用这就是一个典型的“无心识的内存引用”。为了防止这些“无心识的内存引用”,咱们应该了解对象相互引用的时候是存在怎样的依赖关系的。spa
下面咱们在看看一个简单的栈实现例子:code
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; } private void ensureCapacity(){ if(elements.length == size){ elements = Arrays.copyOf(elements,2*size+1); } } public Object pop(){ if(size == 0){ throw new EmptyStackException(); } Object result = elements[--size]; return result; } }
看似这段程序没有明显的错误,也能运行,可是这里面存在一个内存泄漏问题,若是栈先增加了,而后在收缩,那么栈中弹出的对象将不被当作垃圾回收,即便使用栈的程序不在引用这些对象了,它们也不会被回收,由于栈内部维护着对这些对象的过时引用,所谓的过时引用是指永远不在会被解除的引用,这里就是凡在elements数组的活动部分以外的任何引用都是过时的。对象
对于上述这些修复的方法仍是比较简单的,一旦对象是过时引用,只须要清空这些引用便可,对应上述例子中的Stack而已,只要一个单元被弹出栈,那就是过时引用,只须要在pop方法的return result上面加上elements[size] = null;便可。blog
固然,咱们不要由于惧怕内存泄漏而在全部的地方都手动回收内存,这样会致使咱们的代码凌乱臃肿,不利于管理,咱们应该把目标集中在那些长声明周期的变量中,哪些是长生命周期的变量呢,最明显的一个就是static修饰的变量,咱们应该把目光放在这些变量上。 生命周期