Kotlin JNI加载库正常但调用外部函数报UnsatisfiedLinkError
根因
该问题是**C++ 名字修饰(Name Mangling)**导致的JNI符号匹配失败:
- JVM查找native方法实现时,会按照JNI约定的C风格命名规则匹配动态库导出符号,即无编译器额外修饰的
Java_包名_类名_方法名格式符号。 - 从nm输出可见,
startProxy对应的导出符号是__Z51Java_abc_de_fg_jni_ProxyControls_startProxyP7JNIEnv_P8_jobject,前缀_Z是C编译器对函数名做修饰后的典型特征:C为了支持函数重载等特性,会在编译时修改函数名、把参数类型信息编码到符号名里,最终导出的符号不符合JNI的命名匹配规则。 JNI_OnLoad能被正常调用是因为它的导出符号是未被修饰的_JNI_OnLoad,符合动态库入口的查找规则,因此库加载流程无异常,但JVM始终找不到匹配startProxy的正确符号,调用时就会抛出UnsatisfiedLinkError。
修复方案
- 对所有JNI导出的函数添加
extern "C"声明,告诉C++编译器按照C语言的规则导出这些函数,不做名字修饰。
可以用块统一包裹所有JNI实现:
也可以单独给单个函数加声明:extern "C" { JNIEXPORT void JNICALL Java_abc_de_fg_jni_ProxyControls_startProxy(JNIEnv *env, jobject obj) { // 原有业务实现 } // 其余JNI方法统一放在该块内即可 }extern "C" JNIEXPORT void JNICALL Java_abc_de_fg_jni_ProxyControls_startProxy(JNIEnv *env, jobject obj); - 重新编译动态库后,用nm命令验证导出符号,此时
startProxy对应的导出符号应该为_Java_abc_de_fg_jni_ProxyControls_startProxy(无_Z前缀的修饰内容,macOS平台C符号默认带前导下划线属于正常情况,JVM会自动处理),此时JVM即可正常匹配到native实现,调用不再报错。
内容的提问来源于stack exchange,提问作者Shazniq
相关产品推荐
相关产品推荐

