随笔分类
垃圾回收器
Garbage Collectors
具体算法的落地实现.
概述
JVM并没有在垃圾收集器中进行过多的规定,可以有不同的厂商、不同的版本的JVM来实现.
由于JDK的版本处于高速 迭代过程中,因此Java发展至今已经衍生了众多的GC版本.
从不同角度分析垃圾收集器,可以将GC分为不同的类型.
Java不同版本的新特性.
- 语法层面:Lambda表达式、switch、自动装箱、自动拆箱、enum...
- API层面:Stream API、新的日期时间、Optional、String、集合框架
- 底层优化:JVM的优化、GC的变化、元空间、静态域、字符串常量池
分类
垃圾回收器实质上是和具体的JVM紧密相连着的.
ZGC极有可能会在未来不久时间会去取代G1.
七种经典的垃圾收集器
- 串行回收器:Serial、Serial Old
- 并行回收器:ParNew、Parallel Scavenge、Parallel Old
- 并发回收器:CMS、G1
值得注意的是,Parallel Scavenge、Parallel Old、G1其各自使用的框架以及底层实现是区别于其它的垃圾收集器的,也就是说二者是无法在一起工作的
详细见下图
组合关系
根据具体的应用场景来选择最适合的Garbage Collector.
评价GC的性能指标
吞吐量:运行用户代码的时间占总运行时间的比例
- 总运行时间 = 程序运行时间 + 内存回收时间
- 垃圾收集开销:吞吐量的补数,垃圾收集所用时间与总运行时间之比.
暂停时间:执行垃圾收集时,程序的工作线程被暂停的时间
- 收集频率:相对于应用程序的执行,GC发生的频率
内存占用:Java堆区所占的内存大小
- 快速:一个对象从诞生到被回收所经历的时间.
这三者构成一个"不可能三角
",三者总体的表现会随着技术进步而越来越好. 一款优秀的收集器通常最多同时满足其中的两项.
这三项里,暂停时间的重要性日益凸显. 因为随着硬件发展,内存占用多些越来越能容忍,硬件性能的提升也有助于降低收集器运行时对应用程序的影响,即提高了吞吐量. 而内存的扩大,对延迟反而带来负面效果.
简单来说,主要抓住两点:
吞吐量
暂停时间
注重吞吐量
这种情况下,应用程序能容忍较高的暂停时间,因此,高吞吐量有着更高的时间基准,快速响应是不必考虑的.
吞吐量优先,意味着在单位时间内,STW的时间最短:0.2 + 0.2 = 0.4
高吞吐量可以高效率地利用CPU时间,尽快完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务. 因此,常见在服务器环境中使用. 例如,那些执行批量处理、订单处理、工资支付、科学计算的应用程序.
服务器端的硬件配置
通常较高.
注重低延迟
针对指标 STW
尽可能让程序线程的暂停时间短一些,即减少一次GC耗费的时间,代价便是GC的频率高了(还涉及了CPU的线程切换开销),与注重吞吐量相比,此更注重于用于体验.
0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 = 0.5
吞吐量 VS 低延迟
高吞吐量较好因为这会让应用程序的最终用户感觉只有应用程序线程在做"生产性"工作,直觉上,吞吐量越高程序运行越快.
低暂停时间(低延迟)较好因为从最终用户的角度来看不管是GC还是其他原因导致一个应用被挂起始终是不好的. 这取决于应用程序的类型,有时候甚至短暂的200ms暂停都有可能打断终端用户体验. 因此,具有低的较大暂停时间是非常重要的,特别是针对一些交互式应用程序
不幸的是"高吞吐量"和"低暂停时间"是一对相互竞争
的目标(矛盾)。
-
因为如果选择
以吞吐量优先
,那么必然需要降低内存回收的执行频率,但是这样会导致GC需要更长的暂停时间来执行内存回收。 -
相反的,如果选择
以低延迟优先
为原则,那么为了降低每次执行内存回收时的暂停时间,也只能频繁地执行内存回收,但这又引起了年轻代内存的缩减和导致程序吞吐量的下降
在设计(或使用)GC算法时,我们必须确定我们的目标:一个GC算法只可能针对两个目标之一(即只专注于较大吞吐量或较短暂停时间),或尝试找到一个二者的折衷.
现在标准:在最大吞吐量优先的情况下,降低停顿时间.
查看默认使用的Garbage Collector
-
-XX:+PrintCommandLineFlags
:查看命令行相关参数(包含使用的垃圾收集器)-
JDK 8 more使用的是Parallel GC 和 Parallel Old GC
-
JDK 9及其之后默认使用的便是G1
# JDK 8 C:\Users\MK>jinfo -flag UseParallelGC 8024 -XX:+UseParallelGC C:\Users\MK>jinfo -flag UseParallelOldGC 8024 -XX:+UseParallelOldGC #JDK 11 C:\Users\MK>jinfo -flag UseG1GC 15100 -XX:+UseG1GC //实际上在JDK9及其之后默认使用的便是G1垃圾收集器了.
-
-
使用命令行指令:
jinfo -flag 相关垃圾回收器参数 进程ID