Effective Java笔记第一章创建和销毁对象
第六节消除过期的对象引用
关于内存泄漏方面可以看一下这篇文章内存泄漏,也许会对你理解这篇文章有些许帮助。
1.如果一个栈先增长,然后收缩,那么从栈中弹出的对象将不会被当做垃圾回收,即使使用栈的程序不再引用这些对象,他们也不会被回收。应为栈内部维护着对这些对象的过期引用。过期引用是指永远也不会再被解除的引用。
2.在支持垃圾回收的语言中,内存泄漏是很隐蔽的(我们称这类内存泄漏为"无意识的对象保持"更恰当)。如果一个对象引用被无意识的保留起来了,那么垃圾回收机制不仅不会处理这个对象,而且也不会处理被这个对象所引用的其他对象。
public class Demo1 {
private Object[] elements;
private int size=0;
private static final int DEFAULT_INITIAL_CAPACITY=1;
public Demo1(){
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];
// }
/**
* 在本例中,凡是在element数组的"活动部分"之外的任何引用都是过期的,活动部分是指elements中下标小于size的那些元素
* @return
*/
//消除过期引用
public Object pop(){
if(size==0){
throw new EmptyStackException();
}
//elements[--size]是对象,而result是这个对象的引用,相当于一个指针,也可以说是elements[--size]这个对象的地址。
//对象是长生命周期的,而引用是短生命周期的。长生命周期的对象持有短生命周期的引用,就很可能出现内存泄漏
Object result= elements[--size];
//Eliminate obsolete reference 消除过时的引用
elements[size]=null;
return result;
}
//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);
}
}
public static void main(String[] args) {
Demo1 demo1 = new Demo1();
// System.out.println(demo1.elements.length);
// System.out.println(demo1.size);
demo1.push(1);
// System.out.println(demo1.elements.length);
// System.out.println(demo1.size);
demo1.push(2);
// System.out.println(demo1.elements.length);
// System.out.println(demo1.size);
Object pop = demo1.pop();
demo1.push(2);
// System.out.println(pop);
for (int i = 0; i < demo1.elements.length; i++) {
System.out.println(demo1.elements[i]);
}
}
}
2.清空过期引用的另一个好处是,如果他们以后又会被错误的解除引用,程序就会立刻抛出NullPointException异常,而不是悄悄地错误运行下去。清空对象引用应该是一种例外,而不是一种规范行为。消除过期引用最好的方法是让包含该引用的变量结束其生命周期。
3.一般来说,只要类是自己管理内存,程序员就应该警惕内存泄露问题。内存泄漏还有另外两个常见的来源:1.缓存2.监听器和其他回调。