标签:算法 垃圾收集 ati 基于 优缺点 系统 语言 动态 有用
2.1.哪些内存需要回收?
jvm的内存结构包含五大区域:程序计数器、虚拟机栈、本地方法栈、堆区、方法区。其中,程序计数器、虚拟机栈、方法栈3个区域随线程而生,随线程而灭,因此这届个区域的内存和回收都具备确定性,就不需要过多回收的问题,因为方法结束时,内存自然就跟着回收了,而java堆区和方法区不一样,这部分内存的分配和回收是动态的,正是垃圾收集器所需关注的部分。
垃圾收集器在对堆区,和方法区进行回收之前,首先要确定这些区域的对象哪些可以回收,哪些暂时不能回收,这就要用到判断对象是否存活的算法。
2.2引用计数算法
2.2.1算法分析
引用计数法是垃圾收集器的早期策略。在这种方法中,堆中每个对象实例都有一个引用计数。当一个对象被创建时,就将该对象实例分配给一个变量,该变量计数设置为1.当任何其他变量被赋值为这个对象的引用时,计数加1,但当一个对象实例的某个引用超过了生命周期或者被设置为一个新值时,对象实例就会减1.任何计数器为0的对象实例就可以被当作垃圾收集。当一个对象实例被垃圾收集时,它引用的任何对象实例的引用计数减1。
2.2.2优缺点
优点:引用计数收集器可以很快执行,交织在程序运行之中。对程序需要不被长时间打断的实时环境比较有利。
缺点:无法检测出循环引用。如父对象有一个子对象的引用,子对象反过来引用父对象,这样他们的计数永远不可能为0.
2.3 可达性分析算法
可达性分析算法时从离散数学中的图论引入的,程序把所有的引用关系看作一张图,从一个节点GC ROOT开始,寻找对应的引用节点,找到这个节点后,继续寻找这个节点的引用节点,当所有引用节点寻找完毕后,剩余的节点就被认为时没有被引用到的节点,即无用的节点,无用节点将会被判定为可回收对象。
在java语言中,可作为GC Roots的对象包括下面几种:
1)虚拟机中的引用对象(栈帧中的本地变量表)
2)方法区中的类静态属性引用的对象
3)方法区中常量引用的对象;
4)本地方法栈中JNI(native方法)引用的对象。
2.4 java中的引用
无论是通过引用计数算法判断对象的引用的数量,还是通过可达性分析算法判断对象的引用链是否可可达,判定对象是否存活都与引用有关,在java中,将引用分为强引用、软引用、弱引用、虚引用四种,引用强度依次逐级减弱。
1)强引用:在程序代码中普遍存在的,类似Object obj = new Object()这类引用,只要强引用还在,垃圾收集器永远不会回收掉被引用的对象。
2)软引用:用来描述一些还有用但并非必需的对象。对于软引用关联着对象,在系统将要发生内存溢出异常之前,将会把这些对象列入回收范围之中进行第二次回收,如果这次回收后还没有足够的内存,才会抛出内存溢出异常。
3)弱引用:也用来描述非必需对象的,但是它的强度比软引用更弱一些,被弱引用关联的对象只能生存到写一次垃圾收集发生之前,当立即收集器工作时,无论当前内存时候足够,都会回收掉只被弱引用关联的对象。
4)虚引用:也叫幽灵引用或幻影引用,是最弱的一种引用关系,一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个实例对象。它的作用是能在这个对象被搜集其回收时受到一个系统通知。
无论引用计数算法还是可达性分析算法都是基于强引用而言的。
2.5 对象死亡(被回收)前的最后一次挣扎
即使在可达分析算法中不可达的对象,也并非“非死不可”,这时候他们暂时处于“缓刑”阶段,要真正宣告一个对象死亡,至少要经历两次标记过程。
第一次标记:如果对象在进行可达性分析后发现没有与GC roots相连接的引用链,那它将会被第一次标记;
第二次标记:第一次标记后接着会进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。在finalize*(方法中没有重新与引用链建立关联联系,将被进行第二次标记。
第二次标记成功的对象将真的被回收,如果对象在finalize(0方法中与引用重新建立的关联联系,那么将会逃离本次回收,继续存活。
2.6 方法区如何判断是否需要回收
方法区回收的内存有:废弃常量和无用的类。对于废弃常量也可通过引用的可达性来判断,但是对于无用类则需要同时满足下面3个条件:
1)该类所有的实例都已经被回收们就是java堆中不存在该类的任何实例;
2)加载该类的ClassLoader已经被回收;
3)该列对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射机制访问该类的方法。
java类加载机制??????????????????
标签:算法 垃圾收集 ati 基于 优缺点 系统 语言 动态 有用
原文地址:https://www.cnblogs.com/li-jing/p/10840139.html