G1 GC - 导致JVM无响应的大背景I / O - 暂停8秒

问题描述 投票:3回答:1

我们有一个需要几乎实时响应的java应用程序。但我们也看到停顿时间长达8秒。

特殊运行条件:

  1. 在某些时间间隔内,应用程序会将大小高达1.5G的巨大数据快照序列化到磁盘(SSD)中。
  2. 有时,m / c中的某些其他共存过程会发生一些繁重的背景I / O.

我们正在抛弃什么,在这个大型序列化写入发生的时间间隔内,如果GC启动,它会导致6到8秒的巨大暂停,JVM处于完全无响应/冻结状态。

从JFR记录中可以看出,

  1. 所有线程都处于驻留/等待/休眠状态,但正在写入磁盘的状态除外。
  2. G1 GC需要大约200ms才能完成GC。

从GC日志:2018-09-05T18:23:40.277 + 0000:39892.345:应用程序线程停止的总时间:8.3785112秒,停止线程:8.3765855秒

Java版本:java版“1.8.0_181”Java(TM)SE运行时环境(版本1.8.0_181-b25)Java HotSpot(TM)64位服务器VM(版本25.181-b25,混合模式)

问题:

  1. 当GC和后台I / O同时发生时,为什么这样的8秒非GC JVM暂停?
  2. 如何克服这个大停顿?

JFR文件:https://www.filehosting.org/file/details/756217/Run.jfr

java garbage-collection pause g1gc
1个回答
1
投票

你的问题不在GC,而是JVM Stop-The-World机制 - safepoints。在启动GC相关工作之前,JVM会等待所有线程停放在安全点上。

如果您的Java代码使用内存映射文件,则可能需要将其替换为常规IO。内存映射(特别是写重)与安全点机制相关。线程访问存储器映射文件可能被等待写入/读取存储器页面的OS阻止。如果在此时触发GC,则必须等待IO阻塞线程恢复并进入下一个安全点检查。

更新:简单来说,如果在RandomFile / Channel读取方法上阻塞了Java线程,它就不会阻止JVM安全点。但是Java线程在内存映射文件的读/写操作上被阻塞,在线程解除阻塞之前JVM无法进入安全点。如果这种访问被包装在循环中,它甚至可能等到循环在某些条件下完成。

引起长时间“停止线程”的另一个问题可能是循环。如果你有一个带有int计数器的简单循环,JVM认为它“很快”并且可能省略循环体内的安全点检查。

© www.soinside.com 2019 - 2024. All rights reserved.