动态扩容引起的空间震荡

现象

服务刚刚启动时 GC 次数较多,最大空间剩余很多但是依然发生 GC,这种情况我们可以通过观察 GC 日志或者通过监控工具来观察堆的空间变化情况即可。GC Cause一般为 Allocation Failure,且在 GC 日志中会观察到经历一次 GC ,堆内各个空间的大小会被调整,如下图所示:

在这里插入图片描述

原因

在 JVM 的参数中 -Xms 和 -Xmx 设置的不一致,在初始化时只会初始 -Xms 大小的空间存储信息,每当空间不够用时再向操作系统申请,这样的话必然要进行一次GC。具体是通过 ConcurrentMarkSweepGeneration::compute_new_size()方法计算新的空间大小:

void ConcurrentMarkSweepGeneration::compute_new_size() {
 assert_locked_or_safepoint(Heap_lock);
 // If incremental collection failed, we just want to expand
 // to the limit.
 if (incremental_collection_failed()) {
 clear_incremental_collection_failed();
 grow_to_reserved();
 return;
 }
 // The heap has been compacted but not reset yet.
 // Any metric such as free() or used() will be incorrect.
 CardGeneration::compute_new_size();
 // Reset again after a possible resizing
 if (did_compact()) {
 cmsSpace()->reset_after_compaction();
 }
}

另外,如果空间剩余很多时也会进行缩容操作,JVM 通过 -XX:MinHeapFreeRatio 和 -XX:MaxHeapFreeRatio 来控制扩容和缩容的比例,调节这两个值也可以控制伸缩的时机,例如扩容便是使用 GenCollectedHeap::expand_heap_and_allocate() 来完成的,代码如下:

HeapWord* GenCollectedHeap::expand_heap_and_allocate(size_t size, bool is_tlab) {
    HeapWord* result = NULL;
 if (_old_gen->should_allocate(size, is_tlab)) {
 result = _old_gen->expand_and_allocate(size, is_tlab);
 }
 if (result == NULL) {
 if (_young_gen->should_allocate(size, is_tlab)) {
 result = _young_gen->expand_and_allocate(size, is_tlab);
 }
 }
 assert(result == NULL || is_in_reserved(result), "result not in heap");
 return result;
}

整个伸缩的模型理解可以看这个图,当 committed 的空间大小超过了低水位 / 高水位的大小,capacity 也会随之调整:
在这里插入图片描述

策略

定位

观察 CMS GC 触发时间点 Old/MetaSpace 区的 committed 占比是不是一个固定的值,或者像上文提到的观察总的内存使用率也可以。

解决

尽量将成对出现的空间大小配置参数设置成固定的,如 -Xms 和 -Xmx,-XX:-MaxNewSize 和 -XX:NewSize,-XX:MetaSpaceSize 和 -XX:MaxMetaSpaceSize 等。

小结

一般来说,我们需要保证 Java 虚拟机的堆是稳定的,确保 -Xms 和 -Xmx 设置的是一个值(即初始值和最大值一致),获得一个稳定的堆,同理在 MetaSpace 区也有类似的问题。不过在不追求停顿时间的情况下震荡的空间也是有利的,可以动态地伸缩以节省空间,例如作为富客户端的 Java 应用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值