[第一阶段]:串行垃圾回收器:jdk1.3.1之前Java虚拟机仅仅只支持Serial收集器
[第二阶段]:并行垃圾回收器:随着多核的出现,Java引入了并行垃圾回收器,充分利用多核性能提升垃圾回收效率
[第三阶段]:并发标记清理回收器CMS:垃圾回收器可以和应用程序同时运行,降低暂停用户线程执行的时间
[第四阶段]:G1(并发)回收器:初衷是在清理非常大的堆空间的时候能满足特定的暂停应用程序的时间,与CMS相比会有更少的内存碎片
1 垃圾回收算法
1-1 标记清除算法
算法概述
优点:回收速度快
缺点:造成内存碎片,无法分配大的连续空间。
算法思想
在Java9之前,Java默认使用的垃圾回收器是ParallelGC,从Java9开始G1作为了默认的垃圾回收器
-
step1: 第一次扫描,通过GC root对象判断堆内存中哪些对象可以进行垃圾回收,进行标记。
-
step2: 第二次扫描, 将那些标记的GC root对象进行垃圾回收,只需要将起始内存地址与终止内存地址放入空闲内存区就行。
1-2 标记整理算法
第一个依旧是标记,第二步会进行一个空间整理,从而不产生碎片。
优点:避免了内存碎片
1-3 复制算法
特点:
将管理的内存分为2块区域,from区域与to区域,将那些不需要回收的对象从from区域拷贝到to区域。复制的过程中完成内存区域的整理。之后交换from和to的指向。
优点:不会产生内存碎片
缺点:需要双倍的内存空间,内存利用率不高,而且拷贝也需要时间。
1-4 三种垃圾回收算法总结
垃圾回收算法 | 优点 | 缺点 |
---|---|---|
标记清除算法(Mark Sweep) | 速度较快 | 产生内存碎片 |
标记整理算法(Mark Compact) | 没有内存碎片 | 速度慢 |
复制算法(Copy) | 没有内存碎片 | 需要占用双倍内存空间 |
注意:实际的JVM垃圾回收算法中上面的三种算法是综合使用的。
2 JVM分代回收算法
2-1 概述
新生代主要由三部分内容组成,分别是Eden区,幸存区from,幸存区to。 通常情况下只有Eden区与幸存区from会存放数目,幸存区to只有垃圾回收时,复制对象会用到。堆内存的新生代进行一次垃圾回收(Minor GC),大部分对象都会都会被回收。
老年代通常存放一些经常被使用的对象,一个对象如果经历多次垃圾回收仍然幸存,那么该对象会从新生代放入老年代。只有新生代内存不足并且老年代内存也不足的时候才会触发full GC对老年代的对象进行垃圾回收。
为什么需要进行划分?
实际环境中,对象的生命周期是不同的,老年代的对象生命周期比较长,可能很长时间才进行一次垃圾回收。新生代的对象生命周期比较短,垃圾回收比较频繁。这种分区法方便采用不同的垃圾回收算法更加有效的进行垃圾回收。
2-2 分代垃圾回收示例
step1:程序刚刚开始运行,产生的对象先放入Eden区,当Eden区放不下的时候。
step2:对Eden区进行Minor GC,并将没有被垃圾回收的对象复制的幸存区To,然后交换幸存区To和幸存区From,第一次垃圾回收的最终的效果如下图所示:
step3: 第一次Minor GC, Eden区又有空间可以分配给新的对象使用,经过一段时间Eden又不够用了,触发第二次Minor GC, 这次垃圾会检查Eden区以及幸存区From哪些对象可以存活,并将这些对象复制到幸存区To,然后交换幸存区To和幸存区From,这个时候Eden区又空了出来,可以放置新的对象。
实际垃圾回收过程中,JVM会对每个对象经过垃圾回收幸存下来的次数进行记录,比如上图中,幸存区的2个对象经过垃圾回收的次数分别是1和2。
step4: 当一些对象经过垃圾回收的次数仍然幸存的次数达到一个阈值(说明这个对象价值比较高),那么这个对象会被移动到老年代。
极端情况考虑:Eden区,from区,老年区都已经满了?
此时会触发Full GC(优先Minor GC,Minor GC依旧内存不够)
2-3 分代垃圾回收的总结
对象首先分配在伊甸园区域
- 新生代空间不足时,触发
minor gc
,伊甸园和from
存活的对象使用copy
复制到 to 中,存活的
对象年龄加 1并且交换from to
minor gc
会引发stop the world
,暂停其它用户的线程,等垃圾回收结束,用户线程才恢复运行
暂停时间较短,由于新生代大部分对象都是垃圾,复制的对象很少,所以效率较高- 当对象寿命超过阈值时,会晋升至老年代,最大寿命是15(4bit,对象头存储)
- 当老年代空间不足,会先尝试触发
minor gc
,如果之后空间仍不足,那么触发full gc,STW
的时
间更长 Full GC
的stop the world
的时间要比MInor GC
时间长,老年代存活对象较多加上空间整理时间,所以停止时间会较长。
如果Full GC
后,空间仍然不足会触发内存不足的异常。
2-4 垃圾回收相关的虚拟机参数
垃圾回收器概述
参数含义 | 参数 | 备注 |
---|---|---|
堆初始大小 | -Xms | |
堆最大大小 | -Xmx 或 -XX:MaxHeapSize=size | |
新生代大小 | -Xmn 或 (-XX:NewSize=size + -XX:MaxNewSize=size ) | NewSize是初始大小,MaxNewSize是最大大小。 |
幸存区比例(动态) | -XX:InitialSurvivorRatio=ratio 和 -XX:+UseAdaptiveSizePolicy | 幸存区的比例,默认是8,假设新生代10M内存,8M划分给Eden区,剩下的二等分,一份from,一份to。 |
幸存区比例 | -XX:SurvivorRatio=ratio | 动态调整幸存区比例 |
晋升阈值 | -XX:MaxTenuringThreshold=threshold | 用于动态调整幸存区比例 |
晋升详情 | -XX:+PrintTenuringDistribution | 用于动态调整幸存区比例 |
GC详情 | -XX:+PrintGCDetails -verbose:gc | 打印详情信息 |
FullGC 前 MinorGC | -XX:+ScavengeBeforeFullGC | 默认在Full GC 前进行一次Minor GC |
2-5 垃圾回收案例分析
情况1:什么都不放的情况
new generation:新生代 tenured generation:老年代
package cn.itcast.jvm.t2;
import java.util.ArrayList;
/**
* 演示内存的分配策略
*/
public class Demo2_1 {
private static final int _512KB