7 个垃圾收集器
垃圾收集器就是内存回收操作的具体实现,HotSpot 有 7 种。因为它们各有各的适用场景。有的属于新生代收集器,有的属于老年代收集器,所以一般都是搭配使用的。关于它们的简单介绍以及分类请见下图。
Serial 收集器
特点:
1.“单线程”操作。会产生“Stop The World”。
2.采用"Stopr the world"。
3.Serial 收集器是虚拟机在 Client模式下的默认新生代收集器,它的优势是简单高效,适合单 CPU 模式。
ParNew 收集器
1.其本身就是 Serial 收集器的多线程版本。虽然除此之外没什么创新之处,但它却是许多运行在 Server 模式下的虚拟机中的首选新生代收集器。
2.除了 Serial 收集器外,只有它能和 CMS 收集器搭配使用。
Parallel Scavenge 收集器
1.新生代收集器,并行的多线程收集器。
2.使用复制算法,
3.可控制吞吐量(Throughput)。
吞吐量 = 运行用户代码时间 / ( 运行用户代码时间 + 垃圾收集时间 )
可调节的虚拟机参数:
-XX:MaxGCPauseMillis:最大 GC 停顿的秒数;-XX:GCTimeRatio:吞吐量大小,一个 0 ~ 100 的数,最大 GC 时间占总时间的比率 = 1 / (GCTimeRatio + 1);-XX:+UseAdaptiveSizePolicy:一个开关参数,打开后就无需手工指定-Xmn,-XX:SurvivorRatio等参数了,虚拟机会根据当前系统的运行情况收集性能监控信息,自行调整。
Serial Old 收集器
1.Serial收集器的老年代版,同为单线程。
2.使用标记整理算法。
3.作为CMS收集容器的后备预案。
Prallel Old 收集器
1.Parallel Old收集器的老年代版,多线程。
2.使用标记-整理算法。
CMS 收集器(Concurrent Mark Sweep)
特点:
1.CMS注重于服务的响应速度,希望系统停顿时间最短。
2.基于“标记-清除”算法实现的。【注1】
3.存在以下几点缺点:
(1)CMS收集器对CPU资源非常敏感。
(2)CMS收集器无法处理浮动垃圾。
(3)由于基于标记-清除算法,所以会产生大量碎片
【注1】 标记-清除算法步骤: 1.初始标记 2.并发标记 3.重新标记 4.并发清除
参数设置:
-XX:+UseCMSCompactAtFullCollection:在 CMS 要进行 Full GC 时进行内存碎片整理(默认开启)-XX:CMSFullGCsBeforeCompaction:在多少次 Full GC 后进行一次空间整理(默认是 0,即每一次 Full GC 后都进行一次空间整理)
关于 CMS 使用 标记 - 清除 算法的一点思考:
之前对于 CMS 为什么要采用 标记 - 清除 算法十分的不理解,既然已经有了看起来更高级的 标记 - 整理 算法,那 CMS 为什么不用呢?最近想了想,感觉可能是这个原因,不过也不是很确定,只是个人的一种猜测。
标记 - 整理 会将所有存活对象向一端移动,然后直接清理掉边界以外的内存。这就意味着需要一个指针来维护这个分隔存活对象和无用空间的点,而我们知道 CMS 是并发清理的,虽然我们启动了多个线程进行垃圾回收,不过如果使用 标记 - 整理 算法,为了保证线程安全,在整理时要对那个分隔指针加锁,保证同一时刻只有一个线程能修改它,加锁的这一过程相当于将并行的清理过程变成了串行的,也就失去了并行清理的意义了。
所以,CMS 采用了 标记 - 清除 算法。
G1 收集器
特点: 1.并行并发。 2.分代收集。 3.空间整合。 4.可预测的停顿。
G1运算步骤
1.初始标记
2.并发标记
3.最终标记
4.筛选回收
GC 日志解读
Java 内存分配策略
新生代和老年代的 GC 操作:
- 新生代 GC 操作:Minor GC
- 发生的非常频繁,速度较块。
- 老年代 GC 操作:Full GC / Major GC
- 经常伴随着至少一次的 Minor GC;
- 速度一般比 Minor GC 慢上 10 倍以上。
优先在 Eden 区分配
- Eden 空间不够将会触发一次 Minor GC;
- 虚拟机参数:
-Xmx:Java 堆的最大值;-Xms:Java 堆的最小值;-Xmn:新生代大小;-XX:SurvivorRatio=8:Eden 区 / Survivor 区 = 8 : 1
大对象直接进入老年代
- 大对象定义: 需要大量连续内存空间的 Java 对象。例如那种很长的字符串或者数组。
- 设置对象直接进入老年代大小限制:
-XX:PretenureSizeThreshold:单位是字节;- 只对 Serial 和 ParNew 两款收集器有效。
- 目的: 因为新生代采用的是复制算法收集垃圾,大对象直接进入老年代可以避免在 Eden 区和 Survivor 区发生大量的内存复制。
长期存活的对象将进入老年代
- 固定对象年龄判定: 虚拟机给每个对象定义一个年龄计数器,对象每在 Survivor 中熬过一次 Minor GC,年龄 +1,达到
-XX:MaxTenuringThreshold设定值后,会被晋升到老年代,-XX:MaxTenuringThreshold默认为 15; - 动态对象年龄判定: Survivor 中有相同年龄的对象的空间总和大于 Survivor 空间的一半,那么,年龄大于或等于该年龄的对象直接晋升到老年代。