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

JNI调用getPackageManager获取nativeLibraryDir出现弱引用已删除错误

问题原因
  • 调用对象错误:getApplicationInfo是PackageManager类的成员方法,代码中错误使用Context实例(即thiz)调用该方法,应该使用之前获取到的instantiatePackageManager(PackageManager实例)调用,方法调用时对象不匹配导致引用错乱。
  • 参数类型不匹配:getApplicationInfo第一个参数是Java的String类型,代码直接传入C原生的const char*类型的packageName,没有转换为jstring,非法的参数引用触发弱引用访问报错。
  • 返回值为野指针:函数内构造的appendedResult是栈上的局部std::string对象,函数执行结束后该对象会被销毁,返回其c_str()指向的是已释放的内存,后续访问会触发内存非法访问问题。
  • JNI引用管理不规范:调用GetStringUTFChars获取字符串后没有调用ReleaseStringUTFChars释放,会造成内存泄漏;同时未主动释放不需要的JNI局部引用,可能引发局部引用表溢出。
解决方案
  1. 修正方法调用对象:调用getApplicationInfo时传入instantiatePackageManager实例而非thiz。
  2. 转换参数类型:将原生C字符串packageName通过NewStringUTF转换为jstring后再作为参数传入。
  3. 修正返回值逻辑:修改函数返回值类型为std::string直接返回字符串对象,避免返回野指针;如果必须返回const char*,需使用malloc分配内存拷贝字符串内容后返回,由调用方负责释放内存。
  4. 补全JNI引用释放逻辑:字符串使用完后调用ReleaseStringUTFChars释放,主动删除不再使用的局部引用。
修正后代码示例
#include <string>
#include <cstdlib>
#include <cstring>

// 方案1:返回std::string,无内存管理负担
std::string getNativeLibPath(JNIEnv* env, jobject thiz, const char* libraryName, const char* packageName) {
    // 转换包名为jstring
    jstring jPackageName = env->NewStringUTF(packageName);
    
    jclass contextClass = env->GetObjectClass(thiz);
    jmethodID getPackageManager = env->GetMethodID(contextClass, "getPackageManager", "()Landroid/content/pm/PackageManager;");
    jobject instantiatePackageManager = env->CallObjectMethod(thiz, getPackageManager);
    
    jclass packageManagerClass = env->GetObjectClass(instantiatePackageManager);
    jmethodID getApplicationInfo = env->GetMethodID(packageManagerClass, "getApplicationInfo", "(Ljava/lang/String;I)Landroid/content/pm/ApplicationInfo;");
    // 这里用PackageManager实例调用方法,不是thiz
    jobject instantiateApplicationInfo = env->CallObjectMethod(instantiatePackageManager, getApplicationInfo, jPackageName, 0);
    
    jclass applicationInfoClass = env->GetObjectClass(instantiateApplicationInfo);
    jfieldID nativeLibraryDir = env->GetFieldID(applicationInfoClass, "nativeLibraryDir", "Ljava/lang/String;");
    auto jLibDir = (jstring) env->GetObjectField(instantiateApplicationInfo, nativeLibraryDir);
    
    const char* libDirStr = env->GetStringUTFChars(jLibDir, nullptr);
    std::string result = std::string(libDirStr) + "/" + libraryName;
    
    // 释放JNI引用
    env->ReleaseStringUTFChars(jLibDir, libDirStr);
    env->DeleteLocalRef(jPackageName);
    env->DeleteLocalRef(jLibDir);
    env->DeleteLocalRef(applicationInfoClass);
    env->DeleteLocalRef(instantiateApplicationInfo);
    env->DeleteLocalRef(packageManagerClass);
    env->DeleteLocalRef(instantiatePackageManager);
    env->DeleteLocalRef(contextClass);
    
    return result;
}

// 方案2:如果必须返回const char*,调用方用完需free
const char* getNativeLibPathC(JNIEnv* env, jobject thiz, const char* libraryName, const char* packageName) {
    std::string result = getNativeLibPath(env, thiz, libraryName, packageName);
    char* buf = (char*)malloc(result.size() + 1);
    strcpy(buf, result.c_str());
    return buf;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 09:57:03