作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO
联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬
学习必须往深处挖,挖的越深,基础越扎实!
阶段1、深入多线程
阶段2、深入多线程设计模式
阶段3、深入juc源码解析
码哥源码部分
码哥讲源码-原理源码篇【2024年最新大厂关于线程池使用的场景题】
码哥讲源码-原理源码篇【揭秘join方法的唤醒本质上决定于jvm的底层析构函数】
码哥源码-原理源码篇【Doug Lea为什么要将成员变量赋值给局部变量后再操作?】
码哥讲源码【谁再说Spring不支持多线程事务,你给我抽他!】
打脸系列【020-3小时讲解MESI协议和volatile之间的关系,那些将x86下的验证结果当作最终结果的水货们请闭嘴】
本章介绍导致GC性能问题的典型情况。相关示例都来源于生产环境, 为演示需要做了一定程度的精简。
说明 :
Allocation Rate
, 翻译为分配速率
, 而不是分配率; 因为不是百分比,而是单位时间内分配的量;同理,
Promotion Rate
翻译为提升速率
;
高分配速率(High Allocation Rate)
分配速率(Allocation rate
)表示单位时间内分配的内存量。通常使用 MB/sec
作为单位, 也可以使用 PB/year
等。
分配速率过高就会严重影响程序的性能。在JVM中会导致巨大的GC开销。
如何测量分配速率?
指定JVM参数: -XX:+PrintGCDetails -XX:+PrintGCTimeStamps
, 通过GC日志来计算分配速率. GC日志如下所示:
0.291: [GC (Allocation Failure)
[PSYoungGen: 33280K->5088K(38400K)]
33280K->24360K(125952K), 0.0365286 secs]
[Times: user=0.11 sys=0.02, real=0.04 secs]
0.446: [GC (Allocation Failure)
[PSYoungGen: 38368K->5120K(71680K)]
57640K->46240K(159232K), 0.0456796 secs]
[Times: user=0.15 sys=0.02, real=0.04 secs]
0.829: [GC (Allocation Failure)
[PSYoungGen: 71680K->5120K(71680K)]
112800K->81912K(159232K), 0.0861795 secs]
[Times: user=0.23 sys=0.03, real=0.09 secs]
计算 上一次垃圾收集之后
,与下一次GC开始之前
的年轻代使用量, 两者的差值除以时间,就是分配速率。 通过上面的日志, 可以计算出以下信息:
- JVM启动之后
291ms
, 共创建了33,280 KB
的对象。 第一次 Minor GC(小型GC) 完成后, 年轻代中还有5,088 KB
的对象存活。 - 在启动之后
446 ms
, 年轻代的使用量增加到38,368 KB
, 触发第二次GC, 完成后年轻代的使用量减少到5,120 KB
。 - 在启动之后
829 ms
, 年轻代的使用量为71,680 KB
, GC后变为5,120 KB
。
可以通过年轻代的使用量来计算分配速率, 如下表所示:
Event | Time | Youngbefore | Youngafter | Allocatedduring | Allocationrate |
---|---|---|---|---|---|
1stGC | 291ms | 33,280KB | 5,088KB | 33,280KB | 114MB/sec |
2ndGC | 446ms | 38,368KB | 5,120KB | 33,280KB | 215MB/sec |
3rdGC | 829ms | 71,680KB | 5,120KB | 66,560KB | 174MB/sec |
Total | 829ms | N/A | N/A | 133,120KB | 161MB/sec |
通过这些信息可以知道, 在测量期间, 该程序的内存分配速率为 161 MB/sec
。
分配速率的意义
分配速率的变化,会增加或降低GC暂停的频率, 从而影响吞吐量。 但只有年轻代的 minor GC 受分配速率的影响, 老年代GC的频率和持续时间不受 分配速率 (allocation rate
)的直接影响, 而是受到 提升速率 (promotion rate
)的影响, 请参见下文。
现在我们只关心 Minor GC 暂停, 查看年轻代的3个内存池。因为对象在 Eden区分配, 所以我们一起来看 Eden 区的大小和分配速率的关系. 看看增加 Eden 区的容量, 能不能减少 Minor GC 暂停次数, 从而使程序能够维持更高的分配速率。
经过我们的实验, 通过参数 -XX:NewSize
、 -XX:MaxNewSize
以及 -XX:SurvivorRatio
设置不同的 Eden 空间, 运行同一程序时, 可以发现:
- Eden 空间为
100 MB
时, 分配速率低于100 MB/秒
。 - 将 Eden 区增大为
1 GB
, 分配速率也随之增长,大约等于