Java垃圾回收。

一:如何确定哪些对象应该被回收。
   1、引用记数法。在对象中添加一个引用计数器,每当有一个地方引用它时,计数器加一,引用失效时,计数器减一,当计数器为0时,该对象是不可用的。
      i:缺陷:会产生循环引用问题。
   2、可达性分析算法。算法通过一系列的称为“GC Roots” 的对象作为起始点,从这些节点开始向下搜索,搜索走过的路径称为引用链,当一个对象到GC Roots 没有任何引用链时,则该对象是不可用的。
      i:可作为GC Roots 的对象:虚拟机栈(栈帧中的本地变量表)中引用的对象、方法区中类静态属性引用的对象、方法区中常量引用的对象、本地方法栈中 JNI(即一般说的 Native 方法)引用的对象。
二:如何回收垃圾。
   1、标记-清除算法。先标记出所有需要回收的对象,然后统一回收。
      i:优点,基础,简单。
      ii:缺点:效率不高,而且标记清除后会产生大量不连续的内存碎片。
   2、复制算法。该算法将可用的内存分为大小相等的两块,每次只使用一块,当这块内存使用完了,就将存活的对象复制到另一块内存,然后将这块内存全部清理。
      i:优点:不用考虑内存连续的问题。
      ii:缺点:对象存活率高时,效率低。 比较浪费内存。
   3、标记-整理算法。它是标记清除算法的改进,它不仅会清除垃圾对象,而且会进行内存的整理,这样就不会产生内存碎片了。
   4、分代收集算法。上面的几种算法各有优点,所以分代算法的目的是整合上面的算法,以提高垃圾回收的效率。在分代算法中,它根据对象存活周期的不同,将Java堆分成了新生代和老年代,各个年代
                用以最适当的收集算法。在新生代中,每次都有大量的对象死去,就采用复制算法,只需要将少量存活的对象复制即可,也正是因为每次只有少量对象存活这个特性,在复制算法中,
                   也就没有必要将内存五五开,而是一块名为的Eden区域,和两块名为survivor的区域。老年代由于存活率高,可以使用标记清除或标记整理算法。

三:垃圾回收的实现。

  1、OopMap:虚拟机是以可达性分析算法来判断哪些对象需要回收的,所以就需要先找到GC Root,有两种查找 GC Roots 的方法:一种是遍历方法区和栈区查找(保守式 GC)。一种是通过 OopMap 数据结构来记录 GC R o                 ots 的位置(准确式 GC)。很明显,保守式 GC 的成本太高。准确式 GC 的优点就是能够让虚拟机快速定位到 GC Roots。(OopMap 是一种记录GC Roots 的数据结构)

  2、安全点:

    i:概念:程序运行过程中,使OopMap内容变化的指令非常多,所以没有必要对每条指令都生成对应的OopMap,虚拟机选择在某些特定的位置来记录这些信息,这些位置就是安全点。只有在安全点才能触发垃圾回收。

    ii:Stop-The-World:在执行 GC 操作时,所有的工作线程必须停顿。因为可达性分析算法必须是在一个确保一致性的内存快照中进行。如果在分析的过程中对象引用关系还在不断变化,分析结果的准确性就不能保证。

    iii:如何选取安全点:1、循环的末尾。2、方法临返回前。3、调用方法之后。4、抛异常的位置。

    iv:为什么选这些位置:主要的目的就是避免程序长时间无法进入 Safe Point。

    v:如何在 GC 发生时,所有线程都跑到最近的 Safe Point 上再停下来?VM 采取的就是主动式中断:在 GC 发生时,不直接操作线程中断,而是简单地设置一个标志,让各个线程执行时主动轮询这个标志,发现中断标志                                为真时就自己中断挂起。轮询标志的地方和安全点是重合的。

  3、安全区:Safe Point 是对正在执行的线程设定的。如果一个线程处于 Sleep 或中断状态,它就不能响应 JVM 的中断请求,再运行到 Safe Point 上。因此 JVM 引入了 Safe Region。Safe Region 是指在一段代码片段中,引用           系不会发生变化。在这个区域内的任意地方开始 GC 都是安全的。线程在进入 Safe Region 的时候先标记自己已进入了 Safe Region,等到被唤醒时准备离开 Safe Region 时,先检查能否离开,如果 GC 完成了,那           么线程可以离开,否则它必须等待直到收到安全离开的信号为止。

四:垃圾回收器。

  暂缓。

posted @ 2019-11-07 15:33  张玉昊  阅读(177)  评论(0编辑  收藏  举报