这是我参与更文挑战的第19天,活动详情查看:更文挑战
我们最近需要针对将要到来的高流量进行一轮线上所有模块的压测,其中有个模块进行压测后出现了如图的结果:
根据上图单从压测结果上看是无法判断为啥会产生这种结果的。
问题跟进
我们借助阿里云监控可以到看,当时服务cpu 几乎100%,服务ygc和full gc比较频繁。我们在仿真环境上测试100%复现。
- 使用我们常用的命令查看下jvm信息:
- 从图中可以看到确实出现了很多的gc 并且full gc 也频繁;
接下来我们看下gc 信息
jmap -heap 23638
- 发现Survivor space和old generation 内存都占满了;
现在怀疑是否有大对象,于是我又jmap -histo了一下;
使用Jprofiler打开(idea plugins上可找到,平常可本地启动服务查看各种数据)
发现并没有大对象;
- 现在怀疑是不是启动参数配置错误了
jinfo -flags 24445
GCPauseIntervalMillis=8000 印象中这个参数之前都是默认值,查了下g1各种参数:
-XX:MaxGCPauseMillis=xxx
表示每次GC最大的停顿毫秒数,VM将调整Java堆大小和其他与GC相关的参数,以使GC引起的暂停时间短于xxx毫秒,尽可能地保证内存回收花费时间不超过设定值。
请注意,这可能会导致VM降低整体吞吐量(吞吐量=运行用户代码时间/VM总运行时间),并且在某些情况下,VM将无法达到所需的暂停时间目标。
默认情况下,VM没有暂停时间目标值。GC的暂停时间主要取决于堆中实时数据的数量与实时数据量。
该参数应谨慎使用。太小的值将导致系统花费过多的时间进行垃圾回收。原因是为满足最大暂停时间,VM将设置更小的堆,以存储相对少量的对象,来提升回收速率,会导致更高频率的GC。
至此问题终于找到了。
总结
下面我们再简单了解下jvm 的堆 以及常用的g1和cms:
- G1 收集器
面向服务端的垃圾回收器。
优点:并行与并发、分代收集、空间整合、可预测停顿。
运作步骤:
初始标记(Initial Marking)
并发标记(Concurrent Marking)
最终标记(Final Marking)
筛选回收(Live Data Counting and Evacuation)
- CMS 收集器
CMS (Concurrent Mark Sweep) 收集器是一种以获取最短回收停顿时间为目标的收集器。基于 标记 —— 清除 算法实现。
运作步骤:
初始标记(CMS initial mark):标记 GC Roots 能直接关联到的对象
并发标记(CMS concurrent mark):进行 GC Roots Tracing
重新标记(CMS remark):修正并发标记期间的变动部分
并发清除(CMS concurrent sweep)
缺点:对 CPU 资源敏感、无法收集浮动垃圾、标记 —— 清除 算法带来的空间碎片