面试官:过期引用你了解吗?

程序员考拉

共 2817字,需浏览 6分钟

 ·

2020-08-12 10:39


学过JVM的小伙伴一定知道JVM中的四大引用,分别是强引用,软引用,弱引用,虚引用。今天就来给大家说说什么是过期引用?


垃圾回收和内存分配是JVM的两大重点,今天通过一个过期引用的小例子串联起这两块的知识。


先上代码


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) {
        ensureCapcity();
        elements[size++]=e;
    }
    public Object pop(){
        if(size==0){
            throw  new EmptyStackException();
        }
        return elements[--size];
        //Object result=elements[--size];
        //elements[size]=null;
        //return result;
    }

    private void ensureCapcity(){
        if(elements.length==size){
            elements= Arrays.copyOf(elements,2*size+1);
        }
    }
}


public class JprofilerUserTestMain {
    public static void main(String[] args) throws InterruptedException {
        //工具测试主类
        Stack stack=new Stack();
        for (int i = 0; i < 1000; i++) {
            MyClass myClass=new MyClass(i,""+i,(long)i);
            stack.push(myClass);
        }
        //等待15s
        Thread.sleep(15000);
        for (int i = 0; i < 500; i++) {
            stack.pop();
        }
        Thread.sleep(1000000);
    }
}


首先创建了一个栈,栈的内部使用使用数组来实现,其中有两个操作,入栈和出栈,顺序入栈,倒置出栈。在Main函数中 for 循环先放入1000个元素,15s后 出栈500个元素。


对于我们来说 对于出栈的元素,我们往往不会再次从栈内获得。所以上面释放的500个元素 应该在之后被垃圾回收,但是通过Jprofiler工具,我发现在堆中 还是拥有1000个元素。原因是:stack栈中数组500到1000仍保存着释放对象的引用,使得500个对象引用成为过期引用。无法被GC 判断为无用对象进行回收。


如果想要对这些对象进行回收 只需要将pop方法中的数组引用指向为null,在一段时间后系统便会对500个对象进行回收。


总结一下


过期引用指的是永远不会被解除的引用


在我们的stack例子中,凡是在elements数组的”活动范围“之外的任何引用都是过期的,这里的活动部分指的是elements中下标小于size的那些元素。


过期引用导致的问题


过期引用会导致内存泄漏,内存泄露,所谓泄露,就是原来被分配后的内存,在失去利用价值后,应该还给系统以重复利用,但却没还给系统,导致系统可用内存越来越少。


GC如何判断一个对象是否可以回收,使用两种方式,一种是引用计数算法和可达性分析算法,引用计数算法 有着引用之间相互嵌套风险,所以可达性分析算法为主要使用,GC root链中对象对象可达则无法被回收,若多个对象和数组对象 有关,那么垃圾回收机制不仅不会处理这个对象,而且也不会处理被这个对象所引用的其他对象。即使只有少量几个对象引用被无意识的保留下来,也会有许许多多的对象被排除在垃圾回收机制之外。从而对性能造成潜在的巨大影响。


java源码中为避免过期引用如何实现


public synchronized E pop() {
    E obj;
    int     len = size();

    obj = peek();
    removeElementAt(len - 1);

    return obj;
}


public synchronized void removeElementAt(int index) {
    modCount++;
    if (index >= elementCount) {
        throw new ArrayIndexOutOfBoundsException(index + " >= " +
                                                 elementCount);
    }
    else if (index < 0) {
        throw new ArrayIndexOutOfBoundsException(index);
    }
    int j = elementCount - index - 1;
    if (j > 0) {
        System.arraycopy(elementData, index + 1, elementData, index, j);
    }
    elementCount--;
    elementData[elementCount] = null; /* to let gc do its work */
}


stack类继承vector类  进入vector类中可以看到最后一行代码,以及它的注释。


作者:Deciscive
链接:juejin.im/post/6844904071657160711



浏览 38
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报