JVM内存管理-GC总结

基本概念

栈中一般用来存储局部变量,而堆则用来存储对象、数组,java不允许我们显式释放内存,对象和数组总是由JVM的垃圾回收器自动回收,堆被分成以下三个区域:

  1. 新生代
    • Eden(一块)
    • Survivor(二块from、to)
  2. 老年代
  3. 永久代
堆的区域

针对不同的区域,垃圾回收器采用不同的策略进行回收。

通常大多数情况下,对象或数组分配在新生代Eden区,当Eden区没有足够空间时,JVM发起一次Minor GC,将Eden区和其中一块Survivor区内尚存活的对象放入另一块Survivor区域, 如果在Minor GC期间发现新生代存活对象无法放入空闲的Survivor区, 则会使对象提前进入老年代。一些大的对象则直接进入老年代。

永久代用来存放一些静态文件、方法、代码缓存等。

以下原因可能导致Full GC:

  • 老年代满
  • 永久代满
  • System.gc()被显式调用

随着多次GC的进行,对象的年龄会不断增加,并且最终会到老年代。


对象生死判定

垃圾收集器在进行回收前,首先要判断哪些对象已死(可回收),一般是采用可达性分析算法来判定。通过一系列的称为 GC Roots 的对象作为起点, 然后向下搜索; 搜索所走过的路径称为引用链/Reference Chain, 当一个对象到 GC Roots 没有任何引用链相连时, 即该对象不可达, 也就说明此对象是不可用的。


GC算法

GC算法通常可分为分代收集和分区收集,一般主流VM垃圾收集器都采用分代收集。

  • 新生代
    1. 复制算法
    2. 核心:将可用内存按容量划分为大小相等的两块, 每次只用其中一块, 当这一块的内存用完, 就将还存活的对象复制到另外一块上面, 然后把已使用过的内存空间一次清理掉.
  • 老年代
    1. “标记—清除”算法
    2. 核心:该算法分为“标记”和“清除”两个阶段: 首先标记出所有需要回收的对象(可达性分析), 在标记完成后统一清理掉所有被标记的对象.
    3. 标记整理算法
    4. 核心:标记整理算法的标记过程与标记清除算法相同, 但后续步骤不再对可回收对象直接清理, 而是让所有存活的对象都向一端移动,然后清理掉端边界以外的内存.

垃圾收集器分类
  1. 新生代
    • Serial收集器
    • ParNew收集器
    • Parallel Scavenge收集器
  2. 老年代
    • Serial Old收集器
    • Parallel Old收集器
    • CMS收集器
  3. 分区收集-G1收集器