java - G1 GC - 大型后台 I/O 导致 JVM 无响应 - 8 秒暂停

标签 java garbage-collection pause g1gc

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

特殊运行条件:

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

我们观察到的是,DURING 在这个大型序列化写入发生的时间间隔内,如果 GC 偶然启动,它会导致巨大的 6 到 8 秒暂停,JVM 完全无响应/卡住状态。

从 JFR 记录中可以看出,

  1. 除了正在写入磁盘的线程外,所有线程都处于停放/等待/ sleep 状态。
  2. G1 GC 大约需要 200 毫秒才能完成 GC。

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

Java 版本: Java 版本“1.8.0_181” Java(TM) SE 运行时环境(build 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

最佳答案

您的问题不在 GC 中,而是在 JVM Stop-The-World 机制中 - safepoints . JVM 在开始 GC 相关工作之前等待所有线程停放在安全点。

如果您的 Java 代码使用内存映射文件,您可能需要将其替换为常规 IO。内存映射(尤其是重写)与安全点机制配合不佳。访问内存映射文件的线程可能会被等待写入/读取内存页面的操作系统阻塞。如果此时触发GC,则必须等待IO阻塞线程恢复并到达下一个安全点检查。

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

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

关于java - G1 GC - 大型后台 I/O 导致 JVM 无响应 - 8 秒暂停,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52295844/

相关文章:

java - ZGC 垃圾回收器是否支持字符串去重?

ruby - 如何打印字符串并在 Ruby 中出现句号或 "..."时暂停?

c++ - 如何在 for 循环内暂停

scala - 当 Scala "Future"被垃圾收集时会发生什么?

C# 暂停 foreach 循环,直到按下按钮

java - 使用 ant 通过 sciptlet 编译 jrxml

java - 将 HashMap 的键限制为指定字符长度

java - 变量赋值加一个额外的

java - GridBagLayout - 我的列数似乎比指定的少,但为什么?

c# - COM 对象清理