1. 垃圾回收之标记算法

GC

对象被判定为垃圾的标准

  • 没有被其他对象引用

判定对象是否为垃圾的算法

引用计数法

  • 通过判断对象的引用数量决定对象是否可以被回收
  • 每个对象实例都有一个引用计数器,被引用则+1, 完成引用则-1
  • 任何引用计数为0的实例 可以当做垃圾被回收

优点: 执行效率高, 程序受影响比较小 缺点: 无法检测出循环引用的情况,导致内存泄露

可达性分析算法

通过判断对象的引用链是否可达到,来决定对象是否可以被回收

可以作为GC Root的对象:

  • 虚拟机栈中引用的对象(栈帧中的本地变量表)
  • 方法区中的常量引用的对象
  • 方法区中类静态属性引用的对象
  • 本地方法栈中JNI(Native 方法) 的引用对象
  • 活跃线程的引用对象

2. 谈谈你了解的垃圾回收算法

标记-清除法 Mark and Sweep

标记: 从根集合进行扫描,对存活的对象进行标记 清除: 对堆内存从头到尾进行线性遍历,回收不可达对象内存

Mark 阶段 -> Sweep 阶段

存在问题: 碎片化严重,大对象无法找到连续的内存,容易触发下次垃圾回收,outofmemery

复制算法 Coping - 年轻代

适用于对象存活时间比较低的情况

  • 分为对象面和空闲面
  • 对象在对象面上创建
  • 存活对象从对象面复制到空闲面
  • 将对象面所有对象内存清除

有点: 解决了碎片化问题, 顺序分配内存,简单高效,适用于对象存活率低的场景–年轻代

标记整理法 - 老年代

整理: 移动所有存活的对象,且按内存地址次序依次排列,然后将末端内存地址以后的内存全部回收。

优点: 避免了内存不连续,不用设置两块内存互换,适用于存活率高的场景

分代收集算法

垃圾回收算法的组合拳

  • 按照生命周期的不同划分区域, 以采用不同的垃圾回收算法
  • 提高了JVM的垃圾回收效率

Survivor Partitiion 年轻代 复制算法

|Eden Space|From Space| To Space|

Old Generation 老年代 - 标记清除算法 标记整理算法

Tenured Space

Permanen Generation 持久代 -

Permanent Space

GC 的分类

  • Minor GC

    新生代: 尽可能的尽快收集掉那些生命周短的对象

  • Full GC

    主要回收老年代

    Full GC比Minor GC 慢, 但是执行频率低

    新生代 1/3 堆空间 Eden 8/10 | from 1/10 | to 1/10

    老年代 2/3 堆空间

年轻代垃圾回收过程

Eden 区域满会出发一次Minor GC Eden 和 From 区域中的对象会全部移动到 to 区域, 对象的age++,同时清空Eden和From区域

  • 对象移动到老年代 新生代中的对象达到一定的年龄后会移动到老年代 15岁默认 新生代区域Eden和 Suivivor装不下的大对象会直接移动到老年代

这块区域采用的是复制算法, 通多移动堆顶指针实现垃圾回收

对象如何晋升到老年代

  1. 经历一定的minor 次数后依然存活的对象

  2. Survivor 区域存放不下的对象

  3. 新生的大对象-XX: +PretenureSizeThreshold

    常用的调优参数

    -XX: SurvivorRatio Eden 和 Survivor 的比值, 默认为8:1 -XX: NewRatio 老年代和年轻代内存大小的比例 -XX: MaxTenuringThreshold 对象从年轻代晋升到老年代经过GC次数的最大阈值

老年代: 存放生命周期较长的对象

标记清除法 标记整理法

触发Full GC的条件

  1. 老年代空间不足
  2. 永久代空间不足(Before Java7)Java8 以后没有永久代,使用元空间代替
  3. Minor GC时晋升到老年代的平均大小大于老年代的剩余空间
  4. 调用System.gc()时
  5. CMG GC时出现promotion failed, concurrent mode failed
  6. 使用RMI来进行RPC或管理的JDK应用每小时执行一次Full GC