JNI线程与Native线程间安全共享String的问题求助
问题分析与解决方案
核心问题原因
- 进程地址空间隔离:操作系统中每个进程都拥有独立的虚拟地址空间,全局变量
globalInformation在不同进程中是完全独立的实例,内存地址自然不同。你看到的两个不同地址,是不同进程里这个全局变量本身的地址,而非字符串数据的地址。只有调用nativeMethod的进程会初始化自己的globalInformation,其他进程的该变量默认是NULL,这就是打印“Unable to access information value”的直接原因。 - 日志打印混淆:你的日志打印的是
&globalInformation(全局变量自身的内存地址),而非globalInformation指向的字符串数据地址,这会误导你以为是字符串地址变化,实际是不同进程的全局变量本身地址不同。
解决方案
1. 确保每个进程独立初始化
每个需要提供数据的进程,必须由自身的Java代码调用nativeMethod来初始化自己进程内的globalInformation,不能依赖其他进程的初始化操作。
2. 修正日志打印逻辑
把日志打印的内容改成globalInformation(指向字符串的指针值),而非&globalInformation(全局变量自身的地址),这样才能准确跟踪字符串数据的真实地址。
3. 增加线程安全保护
同一进程内,Java线程设置变量和Native线程读取变量属于多线程操作,需要用互斥锁保证读写安全,避免竞态条件导致的异常。
4. 内存泄漏防护
在进程退出或不再需要该字符串时,释放globalInformation指向的堆内存,避免内存泄漏。
修正后的Native代码示例
#include <pthread.h> #include <cstring> #include <android/log.h> #define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, "JNI_TAG", __VA_ARGS__) // 全局变量与互斥锁 char* globalInformation = nullptr; pthread_mutex_t info_mutex = PTHREAD_MUTEX_INITIALIZER; JNIEXPORT void JNICALL Java_className_nativeMethod(JNIEnv* env, jobject obj, jstring information) { pthread_mutex_lock(&info_mutex); // 先释放旧内存(如果存在) if (globalInformation != nullptr) { delete[] globalInformation; globalInformation = nullptr; } const char* temp = env->GetStringUTFChars(information, nullptr); if (temp != nullptr) { globalInformation = new char[strlen(temp) + 1]; strcpy(globalInformation, temp); ALOGI("Set globalInformation data address: %p\n", globalInformation); env->ReleaseStringUTFChars(information, temp); } pthread_mutex_unlock(&info_mutex); } void printInformation() { pthread_mutex_lock(&info_mutex); ALOGI("Read globalInformation data address: %p\n", globalInformation); if (globalInformation == nullptr) { ALOGI("Unable to access information value\n"); } else { ALOGI("%s\n", globalInformation); } pthread_mutex_unlock(&info_mutex); } // 可选:在进程退出时调用此函数释放内存 void releaseGlobalInformation() { pthread_mutex_lock(&info_mutex); if (globalInformation != nullptr) { delete[] globalInformation; globalInformation = nullptr; } pthread_mutex_unlock(&info_mutex); pthread_mutex_destroy(&info_mutex); }
额外注意事项
- 不要试图在进程间共享Native层的内存指针:进程间的虚拟地址空间完全隔离,直接传递指针毫无意义,必须通过IPC机制传递实际数据(比如Binder传递字符串),而非指针。
- JNI环境变量
JNIEnv不能跨线程使用:如果printInformation是在非JNI调用线程执行,需要先通过AttachCurrentThread获取当前线程的JNIEnv(不过你的场景中printInformation只是读取已复制的字符串,不需要JNI环境,所以没问题)。
内容的提问来源于stack exchange,提问作者Ammar Rupawala
相关产品推荐
相关产品推荐

