我们有一个Java应用程序,几乎需要实时响应。但我们也看到停顿了8秒。
特殊运行条件:
我们正在观察的情况,在期间,发生这种大序列化写入的时间间隔,如果偶然发生GC启动,这会导致6到8秒的巨大暂停,则JVM完全没有响应/冻结状态。
从JFR记录显示,
来自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,混合模式)
问题:
JFR文件:https://www.filehosting.org/file/details/756217/Run.jfr
答案 0 :(得分:1)
您的问题不在GC中,而是JVM Stop-The-World机制-safepoints。 JVM等待所有线程停在安全点上,然后再开始与GC相关的工作。
如果您的Java代码正在使用内存映射文件,则可能需要用常规IO替换它。内存映射(尤其是繁重的写操作)在安全点机制中起着非常不利的作用。等待写/读内存页面的操作系统可能阻止线程访问内存映射文件。如果此时触发了GC,则必须等待IO阻塞线程才能恢复并到达下一个安全点检查。
更新:简单来说,如果Java线程在RandomFile
/ Channel
读取方法上被阻止,则不会阻止JVM安全点。但是如果Java线程在对内存映射文件的读/写操作上被阻止,则JVM在线程被取消阻止之前无法进入安全点。如果将此类访问包装在循环中,则它甚至可能在某些情况下等到循环结束。
另一个导致长时间“停止线程占用”的问题可能是循环。如果您具有带有int计数器的简单循环,则JVM会将其视为“快速”的,并且可以在循环体内省略安全点检查。