美文网首页
垃圾回收器

垃圾回收器

作者: 冉桓彬 | 来源:发表于2019-04-28 21:26 被阅读0次

    持续更新...

    打算从以下几个方面学习垃圾回收器相关的知识

    1、如何判断对象是否存活;
    2、垃圾收集算法;
    3、四种引用;
    4、Object.finalize();
    

    一、GC两种算法

    1.1 引用计数算法

    给对象中添加一个引用计数器, 每当有一个地方引用它时, 计数器值就加1, 当引用失效时, 计数器值就减1; 任何时刻计数器为0的对象就是不可能再被使用的.

    1.2 可达性分析算法

    1、通过一系列的称为"GC Roots"的对象作为起始点, 从这些节点开始向下搜索, 搜索所走过的路径称为引用链, 当一个对象到GC Roots没有任何引用链相连时, 则证明此对象是不可用的.
    2、在java语言中, 可作为GC Roots的对象包括下面几种:
      (1) 虚拟机栈(栈帧中的本地变量表)中引用的对象;
      (2) 方法区中类静态属性引用的对象;
      (3) 方法区中常量引用的对象;
      (4) 本地方法栈中JNI(即一般说的Native方法)引用的对象;

    二、四种引用

    2.1 强引用

    只要强引用还存在, 垃圾收集器永远不会回收掉被引用的对象.

    2.2 软引用

    &emp;&emp;软引用是用来描述一些还有用但并非必需的对象. 对于软引用关联着的对象, 在系统将要发生内存溢出异常之前, 将会把这些对象列进回收范围之中进行第二次回收.

    2.3 弱引用

    当垃圾收集器工作时, 无论当前内存是否足够, 都会回收掉只被弱引用关联的对象.

    2.4 虚引用

    为一个对象设置虚引用关联的唯一目的就是能在这个对象呗收集器回收时收到一个系统通知.

    2.5 引用队列

    在初始化软/弱引用时, 如果将他们与引用队列相互关联起来了, 那么当对象被回收时, 这个软/弱引用将会被添加到引用队列中.

    2.6 Object.finalize()

      如果GC触发时, 发现要回收的对象重写了finalize()方法, 那么会将该对象添加到F-Queue队列中, 并由Finalizer线程去执行他的finalize方法, 稍后GC将对F-Queue中的对象进行第二次小规模的标记.

    三、垃圾收集算法

    3.1 标记-清楚算法

      1、首先标记出所有需要回收的对象, 在标记完成后统一回收所有被标记的对象;
      2、效率问题: 标记和清除两个过程的效率都不高;
      3、空间问题: 标记清除之后会产生大量不连续的内存碎片, 空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时, 无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作;

    3.2 复制算法

      1、将可用内存按容量分为大小相等的两块, 每次只使用其中的一块. 当这一块的内存用完了, 就将还存活着的对象复制到另外一块上面, 然后再把已使用过的内存空间一次清理掉.
      2、将内存分为一块较大的Eden空间和两块较小的Survivor空间, 当回收时, 将Eden和Survivor中还存活着的对象一次性地复制到另外一块Survivor空间上, 最后清理掉Eden和刚才用过的Survivor空间.

    3.3 标记-整理算法

      首先标记出所有需要回收的对象, 标记完成以后让所有的存活的对象都向一端移动, 然后直接清理
    掉端边界以外的内存.

    1. 分代收集算法:
      (1) 根据对象存活周期的不同将内存划分为新生代和老年代.
      (2) 根据各个年代的特点采用最适当的收集算法.
      (3) 在新生代中每次垃圾收集时都发现有大批对象死去, 只有少量存活, 那就选用复制算法, 只需要付
      出少量存活对象的复制成本就可以完成收集;
      (4) 老年代中因为对象存活率高、没有额外空间对它进行分配担保, 就必须使用"标记-清理"或者
      "标记-整理"算法来进行回收;

    四、内存分配与回收策略

    1. 对象优先在Eden分配:
           大多数情况下, 对象在新生代Eden区中分配, 当Eden区没有足够空间进行分配时, 虚拟机将发起
       一次Minor GC. GC触发时首先尝试将存活对象复制到Survivor中, 如果Survivor中不够分配内存, 
       则通过分配担保机制提前转移到老年代去;
    2. 大对象直接进入老年代:
           需要大量连续内存空间的java对象. 大对象对虚拟机的内存分配来说就是一个坏消息, 大对象直接
       在老年代分配, 这样做的目的是避免在Eden区以及两个Survivor区之间发生大量的内存复制;
    3. 长期存活的对象将进入老年代:
           虚拟机采用了分代收集的思想来管理内存, 那么内存回收时就必须能识别哪些对象应放在新生代, 
       哪些对象应放在老年代. 为了做到这点, 虚拟机给每个对象定义了一个对象年龄计数器. 如果对象在
       Eden出生并经过第一次Minor GC后仍然存活, 并且能被Survivor容纳的话, 将被移动到Survivor空
       间中, 并且对象的年龄设为1. 对象在Survivor区中每"熬过"一次Minor GC, 年龄就增加1岁, 当它的
       年龄增加到一定程度(默认为15岁), 就将会被晋升到老年代中.
    

    相关文章

      网友评论

          本文标题:垃圾回收器

          本文链接:https://www.haomeiwen.com/subject/qblogqtx.html