02.25 面试官:过期引用你了解吗?说说看...

  • <strong>
  • <strong>
  • <strong>
  • <strong>
  • <strong>

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

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

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

先上代码

<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) {        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);        }    }}/<code>
<code>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);    }}/<code>

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

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

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

总结一下

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

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

过期引用导致的问题

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

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

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

<code>public synchronized E pop() {    E       obj;    int     len = size();    obj = peek();    removeElementAt(len - 1);    return obj;}/<code>
<code>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 */}/<code>

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


作者:cpp-wen
原文链接:https://juejin.im/post/5e547264e51d4526de3927be


分享到:


相關文章: