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


分享到:


相關文章: