JNI GetPrimitiveArrayCritical 导致 JVM 崩溃

问题描述 投票:0回答:2

我有一个java程序调用JNI函数来对字节数组执行计算,返回一个长数组。该程序在 Oracle JDK 1.8.0_221 上运行。为了测试吞吐量,我使用 JMH 1.21

在大小为 64M 的同一字节数组上运行代码进行多次迭代

java端代码如下

public long[] compute(byte[] input, int resultSize) {
    long[] result = new long[resultSize];
    nativeCompute(input, result);
    return result;
}

native void nativeCompute(byte[] input, long[] output);

JNI 代码只是从 Java 数组获取指针并将其传递给计算函数

JNIEXPORT void JNICALL Java_NativeCompute_nativeCompute
    (JNIEnv *env, jobject self, jbyteArray input, jlongArray result) {

//  uint8_t *data = (uint8_t *) env->GetPrimitiveArrayCritical(input, 0);
//  uint64_t *localres = (uint64_t *) env->GetPrimitiveArrayCritical(result, 0);
    jbyte *data = env->GetByteArrayElements(input, 0);
    jlong *localres = env->GetLongArrayElements(result, 0);

    compute((uint8_t *) data, (uint64_t *) localres);

//  env->ReleasePrimitiveArrayCritical(input, data, JNI_ABORT);
//  env->ReleasePrimitiveArrayCritical(result, localres, JNI_COMMIT);
    env->ReleaseLongArrayElements(result, localres, JNI_COMMIT);
    env->ReleaseByteArrayElements(input, data, JNI_ABORT);
}

我使用

GetByteArrayElements
GetLongArrayElements
从java数组中获取指针,程序运行良好。

为了避免数组复制,我尝试切换到

GetPrimitiveArrayCritical/ReleasePrimitiveArrayCritical
,如注释掉的代码中所示。性能提高了 15%,但 JVM 在运行一些(30-150)次迭代后崩溃了。错误日志如下

# Run progress: 0.00% complete, ETA 00:12:30
# Fork: 1 of 5
# Warmup Iteration   1: 7.436 ops/s
# Warmup Iteration   2: #
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007fe4b14ca554, pid=14023, tid=0x00007fe49baa2700
#
# JRE version: Java(TM) SE Runtime Environment (8.0_221-b11) (build 1.8.0_221-b11)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.221-b11 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# V  [libjvm.so+0x987554][thread 140620183496448 also had an error]
[thread 140619839837952 also had an error]
  oopDesc* PSPromotionManager::copy_to_survivor_space<false>(oopDesc*)+0x204
#

当我切换回

Get<XX>ArrayElements
时,这个错误就消失了。但我仍然希望获得 15% 的性能提升
GetPrimitiveArrayCritical

如有任何建议,我们将不胜感激。谢谢!

2019 年 8 月 20 日更新

谢谢大家的建议!我已按照您的建议进行了尝试,这里有一些更新。

  1. 我添加了代码来检查指针是否为 NULL。它们不为空。

  2. 该错误仅发生在JMH环境中。当我独立运行代码并重复 2000 次迭代时,没有错误。

  3. 我注释掉了计算,错误就消失了。看起来崩溃是由数组溢出引起的。我仔细检查了代码,发现 当输入元素的数量是 64 的倍数时,我的代码将意外地跨越结果数组的边界。我修复了该错误,现在错误消失了。我应该仔细检查代码以避免这种愚蠢的错误。

虽然还不清楚为什么错误只发生在JMH环境中,但我想我们已经找到了根本原因,谢谢大家的帮助!

java java-native-interface jvm-hotspot jvm-crash
2个回答
1
投票

在我看来,你的计算内容中出现了一些可疑的情况。如果我使用与您相同的方法进行非常简单的测试,我不会遇到任何问题。

此外,非常重要的是,

compute
不做任何与
JNI
相关的事情。
PrimitiveArray
附带价格。

当然,对于同一函数的 100 次循环(如下所示:https://github.com/mkowsiak/jnicookbook/tree/master/recipes/recipeNo053),您可以看到加速方面的明显好处

Access via PrimitiveArray
       14.64 real        14.55 user         0.12 sys
Access via ArrayElements
       51.55 real        35.94 user        15.13 sys

快两倍半。无论如何,因为

PrimitiveArray
是有成本的

调用GetPrimitiveArrayCritical后,本机代码 在调用之前不应运行很长一段时间 释放PrimitiveArrayCritical。

我会重新考虑使用

PrimitiveArray
来表示这种数组大小是否是你真正想要的。

更新

起来!看起来在我准备答案的时候就解决了;)


0
投票

我最近也遇到了这种错误,但不幸的是,我们的项目太大了,而且还依赖于许多其他项目,我们无法确定哪些方法完成了

array overflow
的工作。你有什么建议吗?我们拥有的只是 jvm 崩溃文件,例如:

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007eff7b312b04, pid=100200, tid=0x00007eff62bfa700
#
# JRE version: Java(TM) SE Runtime Environment (8.0_261-b12) (build 1.8.0_261-b12)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.261-b12 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# V  [libjvm.so+0x98eb04]  oopDesc* PSPromotionManager::copy_to_survivor_space<false>(oopDesc*)+0x204
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
#

---------------  T H R E A D  ---------------

Current thread (0x00007eff7402f800):  GCTaskThread [stack: 0x00007eff62afb000,0x00007eff62bfb000] [id=100281]

siginfo: si_signo: 11 (SIGSEGV), si_code: 1 (SEGV_MAPERR), si_addr: 0x00000063f9000000

Registers:
RAX=0x00000063f9000000, RBX=0x00000007ba484dd8, RCX=0x0000000000000004, RDX=0x00007eff7b95c5f8
RSP=0x00007eff62bf9c60, RBP=0x00007eff62bf9cf0, RSI=0x00000007ba484dd8, RDI=0x00007eff74083240
R8 =0x00000063f9000000, R9 =0x0000000493436a5d, R10=0x00007eff7b928ea0, R11=0x0000000000000018
R12=0x00007eff74083240, R13=0x0000000000000001, R14=0x00007eff740832a8, R15=0x0000000000000004
RIP=0x00007eff7b312b04, EFLAGS=0x0000000000010206, CSGSFS=0x0000000000000033, ERR=0x0000000000000004
  TRAPNO=0x000000000000000e

Top of Stack: (sp=0x00007eff62bf9c60)
0x00007eff62bf9c60:   00007eff62bf9cf0 0000000000000400
0x00007eff62bf9c70:   0000000000000038 0000000600000007
0x00007eff62bf9c80:   0000000000000038 0000000000000009
0x00007eff62bf9c90:   00000004934369f8 0000000000000400
0x00007eff62bf9ca0:   0000000000000000 00007eff7b94d712
0x00007eff62bf9cb0:   00007eff62bf9d40 00007eff7b311921
0x00007eff62bf9cc0:   00007efe3009fc20 00007eff74083240
0x00007eff62bf9cd0:   0000000493436a5c 0000000000000001
0x00007eff62bf9ce0:   00007eff740832a8 00007eff7b928eb0
0x00007eff62bf9cf0:   00007eff62bf9d40 00007eff7b312548
0x00007eff62bf9d00:   0ac02d33000076e9 0ac02d34000076e9
0x00007eff62bf9d10:   00007eff62bf9d50 00007eff740837d0
0x00007eff62bf9d20:   0000000000000006 00007eff62bf9d7c
0x00007eff62bf9d30:   0000000000000000 0000000000000005
0x00007eff62bf9d40:   00007eff62bf9dc0 00007eff7b316b2e
0x00007eff62bf9d50:   00007eff74083240 00007efe3009fe00
0x00007eff62bf9d60:   00007eff74083240 0000000000000008
0x00007eff62bf9d70:   00007eff74023f70 0a4bb56a74023f70
0x00007eff62bf9d80:   0a36c37c0000d898 0a36c37c0000d899
0x00007eff62bf9d90:   00007eff62bf9dc0 0000000000000001
0x00007eff62bf9da0:   00007efe3009fe00 00007eff7402f800
0x00007eff62bf9db0:   0000000000000000 00007eff7b94d4a8
0x00007eff62bf9dc0:   00007eff62bf9ed0 00007eff7af4a266
0x00007eff62bf9dd0:   00000000000003d8 00007eff7402fc10
0x00007eff62bf9de0:   00007eff74030038 00007eff7402fc60
0x00007eff62bf9df0:   00007eff62bf9e60 00007eff7402fc50
0x00007eff62bf9e00:   00007eff62bf9e18 00007eff7b4f7eba
0x00007eff62bf9e10:   0000000000000000 0000000000000000
0x00007eff62bf9e20:   00007eff7402f800 00007eff74030040
0x00007eff62bf9e30:   00007eff74030080 00007eff74030090
0x00007eff62bf9e40:   00007eff74030168 00000000000000d8
0x00007eff62bf9e50:   00007eff740302a0 0000000000000001 

Instructions: (pc=0x00007eff7b312b04)
0x00007eff7b312ae4:   8b 45 98 89 c1 41 f6 c0 01 4c 63 f9 4c 89 c0 0f
0x00007eff7b312af4:   85 6f ff ff ff 48 83 e0 fd 48 8d 15 f4 9a 64 00
0x00007eff7b312b04:   48 8b 00 48 c1 e8 03 83 e0 0f 3b 02 0f 82 68 ff
0x00007eff7b312b14:   ff ff 4e 8d 1c fd 00 00 00 00 4d 8b 6c 24 30 4b 

Register to memory mapping:

RAX=0x00000063f9000000 is an unknown value
RBX=0x00000007ba484dd8 is an oop
[C 
 - klass: {type array char}
 - length: 5
RCX=0x0000000000000004 is an unknown value
RDX=0x00007eff7b95c5f8: <offset 0xfd85f8> in /opt/jdk1.8.0_261/jre/lib/amd64/server/libjvm.so at 0x00007eff7a984000
RSP=0x00007eff62bf9c60 is an unknown value
RBP=0x00007eff62bf9cf0 is an unknown value
RSI=0x00000007ba484dd8 is an oop
[C 
 - klass: {type array char}
 - length: 5
RDI=0x00007eff74083240 is an unknown value
R8 =0x00000063f9000000 is an unknown value
R9 =0x0000000493436a5d is pointing into object: 0x0000000493436a50
java.lang.String 
 - klass: 'java/lang/String'
R10=0x00007eff7b928ea0: <offset 0xfa4ea0> in /opt/jdk1.8.0_261/jre/lib/amd64/server/libjvm.so at 0x00007eff7a984000
R11=0x0000000000000018 is an unknown value
R12=0x00007eff74083240 is an unknown value
R13=0x0000000000000001 is an unknown value
R14=0x00007eff740832a8 is an unknown value
R15=0x0000000000000004 is an unknown value


Stack: [0x00007eff62afb000,0x00007eff62bfb000],  sp=0x00007eff62bf9c60,  free space=1019k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V  [libjvm.so+0x98eb04]  oopDesc* PSPromotionManager::copy_to_survivor_space<false>(oopDesc*)+0x204
V  [libjvm.so+0x98e548]  PSPromotionManager::drain_stacks_depth(bool)+0x788
V  [libjvm.so+0x992b2e]  StealTask::do_it(GCTaskManager*, unsigned int)+0x4ce
V  [libjvm.so+0x5c6266]  GCTaskThread::run()+0x1b6
V  [libjvm.so+0x914d12]  java_start(Thread*)+0x102
© www.soinside.com 2019 - 2024. All rights reserved.