JNI应用抛出NoSuchMethodError并触发SIGSEGV崩溃求助
JNI绑定调用时触发NoSuchMethodError与SIGSEGV崩溃
通过CMake构建C++实现JNI绑定,调用CimFileHelper.load方法时,JVM先抛出java/lang/NoSuchMethodError(提示找不到sun.misc.Unsafe.defineClass和prefetchRead方法),随后触发SIGSEGV崩溃,以下是相关代码与错误日志:
Java代码(含native方法)
public class CimFileHelper { static { System.loadLibrary("CimFileHelper"); } public native CimElement[] load(String filePath) throws IOException; }
C++核心实现代码
JNIEXPORT jobjectArray JNICALL Java_com_xxx_CimFileHelper_load (JNIEnv *env, jobject, jstring file_path) { // call load_cim_file } // load xml. int load_cim_file(JNIEnv *env, const char* file_path, jobject (*cim_elem_list)[]) { // call load_elements } // load children elements. int load_elements(JNIEnv *env, xml_node root, jobject (*list)[]) { int count = 0; for (xml_node node = root.first_child(); node; node=node.next_sibling()) { if (node.type() != node_element) continue; jobject cim_elem = load_element(env, node); (*list)[count++] = cim_elem; env->DeleteLocalRef(cim_elem); if (count>3) break; // make a short test. } return count; } // load each element jobject load_element(JNIEnv *env, xml_node node) { jobject cim_elem = new_instance(env, CLS_NAME_CIM_ELEMENT); const char_t* node_tag_w = node.name(); string node_tag = as_utf8(node_tag_w); set_str_value(env, cim_elem, CLS_NAME_CIM_ELEMENT, FIELD_NAME_CIM_ELEMENT_TYPE, node_tag.c_str()); string text = get_element_text(node); if (!text.empty()) set_str_value(env, cim_elem, CLS_NAME_CIM_ELEMENT, FIELD_NAME_CIM_ELEMENT_TEXT, text.c_str()); return cim_elem; } // java new instance. jobject new_instance(JNIEnv *env, const char* class_name) { jclass cls = find_class(env, class_name); jmethodID constructor = find_method(env, class_name, METHOD_NAME_CONSTRUCTOR, SIG_METHOD_EMPTY_VOID); if (!constructor) { cerr<<"Cannot find construtor for "<<class_name<<endl; throw ERR_METHOD_NOT_FOUND; } jobject obj = env->NewObjectA(cls, constructor, new jvalue[0]); return obj; }
运行时错误日志
# A fatal error has been detected by the Java Runtime Environment: # # SIGSEGV (0xb) at pc=0x00007f2f7339061f, pid=82817, tid=0x00007f2fc52ac700 # # JRE version: OpenJDK Runtime Environment (8.0_352-b08) (build 1.8.0_352-352-b08) # Java VM: OpenJDK 64-Bit Server VM (25.352-b08 mixed mode linux-amd64 compressed oops) # Problematic frame: # C [libCimFileHelper.so+0x4961f] load_elements(JNIEnv_*, pugi::xml_node, _jobject* (*) [])+0x11f ... Stack: [0x00007f2fc51ad000,0x00007f2fc52ad000], sp=0x00007f2fc52ab670, free space=1017k Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code) C [libCimFileHelper.so+0x4961f] load_elements(JNIEnv_*, pugi::xml_node, _jobject* (*) [])+0x11f C [libCimFileHelper.so+0x4983c] load_cim_file(JNIEnv_*, char const*, _jobject* (*) [])+0x1c2 C [libCimFileHelper.so+0x1a982] Java_com_xxx_CimFileHelper_load+0x4e j com.xxx.CimFileHelper.load(Ljava/lang/String;)[Lcom/xxx/CimElement;+0 j com.xxx.CimFileHelperTest.main([Ljava/lang/String;)V+59 v ~StubRoutines::call_stub V [libjvm.so+0x65600e] JavaCalls::call_helper(JavaValue*, methodHandle*, JavaCallArguments*, Thread*)+0xf3e V [libjvm.so+0x6b750a] jni_invoke_static(JNIEnv_*, JavaValue*, _jobject*, JNICallType, _jmethodID*, JNI_ArgumentPusher*, Thread*) [clone .isra.195]+0x30a V [libjvm.so+0x6c905e] jni_CallStaticVoidMethod+0x16e C [libjli.so+0x82b9] JavaMain+0xa09 C [libpthread.so.0+0x8ea7] start_thread+0xd7 Java frames: (J=compiled Java code, j=interpreted, Vv=VM code) j com.xxx.CimFileHelper.load(Ljava/lang/String;)[Lcom/xxx/CimElement;+0 j com.xxx.CimFileHelperTest.main([Ljava/lang/String;)V+59 v ~StubRoutines::call_stub ... Internal exceptions (6 events): Event: 0.018 Thread 0x00007f2fc000a800 Exception <a 'java/lang/NoSuchMethodError': Method sun.misc.Unsafe.defineClass(Ljava/lang/String;[BII)Ljava/lang/Class; name or signature does not match> (0x000000076d307cd8) thrown at [/home/centos/8/hotspot/src/share/vm/prims/jni.cpp, line 4014] Event: 0.018 Thread 0x00007f2fc000a800 Exception <a 'java/lang/NoSuchMethodError': Method sun.misc.Unsafe.prefetchRead(Ljava/lang/Object;J)V name or signature does not match> (0x000000076d307fc0) thrown at [/home/centos/8/hotspot/src/share/vm/prims/jni.cpp, line 4014] Event: 1.439 Thread 0x00007f2f78001000 Exception <a 'java/security/PrivilegedActionException'> (0x000000076dd97d00) thrown at [/home/centos/8/hotspot/src/share/vm/prims/jvm.cpp, line 1514] Event: 1.439 Thread 0x00007f2f78001000 Exception <a 'java/security/PrivilegedActionException'> (0x000000076dd980f8) thrown at [/home/centos/8/hotspot/src/share/vm/prims/jvm.cpp, line 1514] Event: 1.440 Thread 0x00007f2f78001000 Exception <a 'java/security/PrivilegedActionException'> (0x000000076dd9af18) thrown at [/home/centos/8/hotspot/src/share/vm/prims/jvm.cpp, line 1514] Event: 1.440 Thread 0x00007f2f78001000 Exception <a 'java/security/PrivilegedActionException'> (0x000000076dd9b310) thrown at [/home/centos/8/hotspot/src/share/vm/prims/jvm.cpp, line 1514] ...
排查与解决思路
1. 优先修复SIGSEGV崩溃
- 非法内存访问定位:崩溃发生在
load_elements函数中(*list)[count++] = cim_elem;行,需确认:load_cim_file传入的cim_elem_list是否已分配足够内存,避免越界访问- 禁止使用未初始化或已释放的指针
- 局部引用误用:代码中存入
list后立即调用DeleteLocalRef,导致list中的引用失效,后续操作必然触发内存错误。需保留局部引用,直到将对象存入JNI数组或转为全局引用后再释放。
2. 处理NoSuchMethodError警告
- Unsafe方法签名不匹配:OpenJDK 8中
sun.misc.Unsafe.defineClass的正确签名包含ClassLoader和ProtectionDomain参数,错误日志中的签名缺失这些参数;prefetchRead签名也可能因JDK版本差异不匹配。 - 定位触发源:检查代码或依赖库是否直接/间接调用了Unsafe的这些方法。如果是第三方库导致,升级库版本或替换为不依赖Unsafe的实现;如果是自有代码,修正方法签名以匹配当前JDK版本。
3. 规范JNI代码实现
- NewObjectA优化:空参数场景下,直接使用
env->NewObject(cls, constructor)更安全,避免不必要的内存分配 - 类与方法校验:确认
find_class和find_method的实现是否正确,比如类的全限定名、方法签名是否完全匹配(构造方法签名为()V) - 异常检查:JNI调用后需及时通过
env->ExceptionCheck()检查异常,避免未处理异常导致后续代码执行错误
内容的提问来源于stack exchange,提问作者Joson_prog
相关产品推荐
相关产品推荐

