Ste*_*eve 15 jit garbage-collection jvm freeze stack-trace
我们最近有一种情况,我们的一个生产JVM会随机冻结.Java进程正在烧毁CPU,但所有可见活动都将停止:没有日志输出,没有写入GC日志,没有响应任何网络请求等.进程将保持此状态直到重新启动.
原来,该org.mozilla.javascript.DToA类,某些输入调用时,会感到困惑,并呼吁BigInteger.pow着巨大的值(例如5 ^ 2147483647),这会触发JVM冻结.我的猜测是,一些大循环,可能是在java.math.BigInteger.multiplyToLen中,在循环中没有安全点检查的情况下进行了JIT.下次JVM需要暂停进行垃圾收集时,它会冻结,因为运行BigInteger代码的线程很长时间都不会达到安全点.
我的问题:将来,我如何诊断这样的安全点问题?杀-3没有产生任何输出; 我认为它依赖于安全点来生成准确的堆栈.是否有任何生产安全的工具可以从正在运行的JVM中提取堆栈而无需等待安全点?(在这种情况下,我真的很幸运,并设法抓住一组堆叠的痕迹BigInteger.pow被调用刚过,但在此之前它的工作它的方式到足够大的输入完全楔入JVM,没有运气中风,我我不确定我们怎么会诊断出这个问题.)
编辑:以下代码说明了问题.
// Spawn a background thread to compute an enormous number.
new Thread(){ @Override public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException ex) {
}
BigInteger.valueOf(5).pow(100000000);
}}.start();
// Loop, allocating memory and periodically logging progress, so illustrate GC pause times.
byte[] b;
for (int outer = 0; ; outer++) {
long startMs = System.currentTimeMillis();
for (int inner = 0; inner < 100000; inner++) {
b = new byte[1000];
}
System.out.println("Iteration " + outer + " took " + (System.currentTimeMillis() - startMs) + " ms");
}
Run Code Online (Sandbox Code Playgroud)
这将启动一个后台线程,等待5秒,然后启动一个巨大的BigInteger计算.在前台,它然后重复分配一系列100,000个1K块,记录每个100MB系列的经过时间.在5秒钟期间,每个100MB系列在我的MacBook Pro上运行大约20毫秒.一旦BigInteger计算开始,我们开始看到交错的长暂停.在一次测试中,暂停依次为175ms,997ms,2927ms,4222ms和22617ms(此时我中止了测试).这与BigInteger.pow()一致,调用一系列更大的乘法运算,每次运算都需要更长时间才能达到安全点.
Mik*_*ail 11
你的问题非常感兴趣.你对JIT是正确的.首先我尝试使用GC类型,但这没有任何效果.然后我试图禁用JIT,一切正常:
java -Djava.compiler=NONE Tests
Run Code Online (Sandbox Code Playgroud)
然后打印出JIT编译:
java -XX:+PrintCompilation Tests
Run Code Online (Sandbox Code Playgroud)
并且注意到在BigInteger类中的一些编译之后问题开始了,我试图从编译中逐个排除方法,最后找到原因:
java -XX:CompileCommand=exclude,java/math/BigInteger,multiplyToLen -XX:+PrintCompilation Tests
Run Code Online (Sandbox Code Playgroud)
对于大型数组,这种方法可能会工作很长时间,问题可能确实存在于安全点.由于某种原因,它们没有插入,但应该在编译代码中.看起来像个bug.下一步应该是分析汇编代码,我还没有这样做.
这不是错误,而是性能特征。JVM 消除了计数循环中的安全点检查,使它们运行得更快。它预计要么
如果它不适合您,可以使用以下标志将其关闭: -XX:+UseCountedLoopSafepoints
在回答标题问题时,您仍然可以停下来探索一个程序gdb,但堆栈跟踪不会那么好。