基本概念
栈中一般用来存储局部变量,而堆则用来存储对象、数组,java不允许我们显式释放内存,对象和数组总是由JVM的垃圾回收器自动回收,堆被分成以下三个区域:
- 新生代
- Eden(一块)
- Survivor(二块from、to)
- 老年代
- 永久代
针对不同的区域,垃圾回收器采用不同的策略进行回收。
通常大多数情况下,对象或数组分配在新生代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垃圾收集器都采用分代收集。
- 新生代
- 复制算法
- 核心:将可用内存按容量划分为大小相等的两块, 每次只用其中一块, 当这一块的内存用完, 就将还存活的对象复制到另外一块上面, 然后把已使用过的内存空间一次清理掉.
- 老年代
- “标记—清除”算法
- 核心:该算法分为“标记”和“清除”两个阶段: 首先标记出所有需要回收的对象(可达性分析), 在标记完成后统一清理掉所有被标记的对象.
- 标记整理算法
- 核心:标记整理算法的标记过程与标记清除算法相同, 但后续步骤不再对可回收对象直接清理, 而是让所有存活的对象都向一端移动,然后清理掉端边界以外的内存.
垃圾收集器分类
- 新生代
- Serial收集器
- ParNew收集器
- Parallel Scavenge收集器
- 老年代
- Serial Old收集器
- Parallel Old收集器
- CMS收集器
- 分区收集-G1收集器