You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JNI调用native函数出现SIGSEGV:二次加载so注册同名函数后调用崩溃

问题根因

你代码中openLib函数里定义的JNINativeMethod methods数组使用了static修饰符,静态局部变量仅会在第一次执行到声明语句时完成初始化,后续调用该函数时都不会重新赋值。
第一次调用openLib加载libcloser.so时,dlsym拿到的doSum函数地址被存入静态的methods数组;第二次调用openLib加载libcloser_2.so时,即使你重新调用dlsym拿到了新库的doSum函数地址,也不会更新到静态methods数组中,调用RegisterNatives时仍然用的是第一次的旧地址。而第一次的libcloser.so已经被dlclose卸载,对应内存地址被系统回收,访问时就会触发SIGSEGV SEGV_ACCERR错误。

排查验证方法

在openLib函数中添加日志打印:

  • 每次调用dlsym后打印拿到的func指针地址
  • 打印methods数组中存储的函数指针地址
    你会发现第二次调用openLib时,两个地址不一致,methods数组中存储的仍是第一次加载libcloser.so时的旧地址,和崩溃日志中的错误地址完全匹配。

修复方案

核心修复

移除JNINativeMethod methods数组的static修饰符,每次调用openLib都重新构造数组,使用当前最新拿到的函数地址完成注册。
修改后代码示例:

void* func = dlsym(handle, "Java_com_android_dynamic_FileGrabberModule_doSum");
// 去掉static修饰,每次调用都重新生成方法数组
JNINativeMethod methods[] = { {"doSum", "()V", func} };
jclass clazz = env->GetObjectClass(module);
int ret = (*env).RegisterNatives(clazz, methods, sizeof(methods)/sizeof(methods[0]));
if (ret == 0) {
    LOGI("registerNatives() Successfull registration, func addr: %p", func);
} else {
    LOGI("registerNatives() Registration Failed, func addr: %p", func);
}
(*env).DeleteLocalRef( clazz );

额外优化校验点

  1. 调用dlsym后判断返回值是否为NULL,如果为空直接返回错误,避免无效地址注册
  2. 每次调用dlclose关闭so库后,将存储so句柄的全局变量置空,避免野指针误用
  3. 增加UnregisterNatives返回值的日志校验,确认旧方法已成功注销
  4. 每次加载新的Module实例时,确认传入的module对象所属的类是动态加载的新类,没有复用旧类对象

内容的提问来源于stack exchange,提问作者Bistaff

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 00:18:02