Android NDK读取存储值偶现为空 仅Android 5.1/6系统复现
问题根因
- 最核心的问题是JNI调用中字符串指针提前释放:你调用
GetStringUTFChars获取到C字符串指针NativeUrlName后,立刻调用了ReleaseStringUTFChars释放该指针,之后再将已失效的野指针传入方法访问内存。这种未定义行为的表现和系统内存管理策略强相关:Android 7+的ART虚拟机对字符串内存的回收策略更保守,野指针大概率还能读到原始值,而Android 5.1/6的Dalvik/早期ART实现中,释放后的内存会被快速回收或复用,因此会随机出现读取空值、乱码甚至崩溃的问题。 - 代码存在多处笔误:
UrlHash类的getUrl方法参数为urlKey,实际访问的是不存在的变量debugUrlKey;JNI层调用的getDebugUrl方法在UrlHash类中未定义,实际应为getUrl。 - 用
std::unordered_map的operator[]查询值存在隐患:如果查询的key不存在,operator[]会自动插入一个空字符串的键值对,返回空值,也会导致偶发空结果。
修复方案
修正后的C++代码如下:
#include <jni.h> #include <string> #include <unordered_map> class UrlHash { std::unordered_map<std::string, std::string> urlHash; public: // 修正变量名笔误,改用find查询避免插入空值 std::string getUrl(std::string urlKey) { auto iter = urlHash.find(urlKey); if (iter != urlHash.end()) { return iter->second; } return ""; // 不存在时可返回自定义默认值 } UrlHash() { urlHash["dummy"] = "dumyValue"; urlHash["dump_url"] = "https://dump.server.com"; urlHash["dump_url2"] = "https://dump2.server.com"; } }; extern "C" JNIEXPORT jstring JNICALL Java_my_com_mynativecapp_UrlProvider_getUrl(JNIEnv *env, jobject thiz, jstring urlName) { UrlHash _debugHashtableInstance; const char *NativeUrlName = env->GetStringUTFChars(urlName, 0); // 先使用字符串,用完再释放 std::string result = _debugHashtableInstance.getUrl(NativeUrlName); env->ReleaseStringUTFChars(urlName, NativeUrlName); return env->NewStringUTF(result.c_str()); }
如果UrlHash实例不需要每次调用都重建,可以改成静态实例减少构造开销,不影响核心逻辑。
内容的提问来源于stack exchange,提问作者nilkash
相关产品推荐
相关产品推荐

