今天给大家讲讲过期引用是个啥?学过JVM的小伙伴一定知道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链中对象对象可达则无法被回收,若多个对象和数组对象 有关,那么垃圾回收机制不仅不会处理这个对象,而且也不会处理被这个对象所引用的其他对象。即使只有少量几个对象引用被无意识的保留下来,也会有许许多多的对象被排除在垃圾回收机制之外。从而对性能造成潜在的巨大影响。
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类中可以看到最后一行代码,以及它的注释。
参考资料
Effective java 第三版