JVM回收对象的判断

哪些内存需要回收?

JVM的内存结构包括五大区域:程序计数器,虚拟机栈,本地方法栈,堆区,方法区

程序计数器,虚拟机栈,本地方法栈:随线程生灭,不用考虑回收。

堆区,方法区:内存分配和回收是动态的,是垃圾收集器关注的部分

在回收对象之前,首先要判断是否存活,需要一些算法来分析。

1 引用计数算法

1.1算法分析 

引用计数是垃圾收集器中的早期策略

每个对象都有一个引用计数器,当任何一个变量被赋值为这个对象的引用时,计数加1。

当一个对象的某个引用超过的生命周期,或者被赋一个新值时,计数减1。

当一个对象的引用计数器0时,就看可以被当做垃圾收集。

当一个对象被垃圾回收时,它引用的任何对象的计数器都减1

1.2优缺点

优点:引用计数器可以很快地执行,交织在程序运行中,对程序不能被长时间打断的实时环境比较有利。

缺点:无法检测出循环引用。如,两个对象的某个成员变量分别引用这两个对象。如

        MyObject object1 = new MyObject();
        MyObject object2 = new MyObject();
          
        object1.object = object2;
        object2.object = object1;
          
        object1 = null;
        object2 = null;

则这两个对象不会被回收

2 可达性分析算法

程序把所有的引用关系看成是一张图,从一个节点GC Root开始,寻找对应的引用节点,找到这个节点之后,继续寻找这个节点的引用节点,当所有的引用节点寻找完毕后,剩余的节点就是无用的节点,判断为是可回收的对象。

在Java语言中,可作为GC Root的对象包括:

虚拟机栈(栈帧中的本地变量表)中引用的对象

▲方法区中类静态属性引用的对象

▲方法区中常量引用的对象

▲本地方法栈中JNI(即一般所说的Native方法)引用的对象

3  Java中的引用

无论是引用计数法,还是可达性分析,判断对象是否存活都与引用有关

在Java语言中,将引用分为强引用,软引用,弱引用,虚引用四种,且引用强度依次减弱。

 

强引用:程序代码中普遍存在的,类似Object obj = new Object()的,只要强引用还在,垃圾收集器永远不会回收被引用的对象。

 

软引用:用来描述一些还有用但并非必需的对象。被软引用关联着的对象,在系统将要发生内存溢出之前,会进行回收,如果回收之后还没有足够的内存,才会抛出内存溢出异常。

 

弱引用:描述一些非必需的对象,只能生存到下一次垃圾收集发生之前,就会被回收

 

虚引用不影响对象的生存时间,也无法通过虚引用取得对象实例。它的作用是能在这个对象被垃圾收集器回收时收到一个系统通知。

 

4  回收前的挣扎

即使在可达性分析中不可达的对象,也不会被马上回收,至少需要经历两次标记过程

第一次标记:可达性分析中不可达,没有与GC Roots相连接的引用链,将会被第一次标记。

第二次标记:第一次标记后会进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。当对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过,则认为么有必要执行。如果在finalize()方法没有重新与引用链建立关联关系的,将会被进行第二次标记。

5 方法区的回收

方法区回收的内容:废弃常量无用的类

废弃常量也可通过引用的可达性分析来判断。

无用类的判断需要同时满足三个条件:


         ●该类的所有实例都已经被回收,即Java堆中不存在该类的任何实例。

         ●该类的加载器ClassLoader已经被回收

         ●该类的类对象(Class对象)没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。

但满足这三个条件的无用类仅代表可以回收,但不是必然回收,这和对象回收不一样,是否对类进行回收,在HotSpot虚拟机中可以配置参数。

猜你喜欢

转载自blog.csdn.net/ChaunceyChen/article/details/86569266