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

JNI线程与Native线程间安全共享String的问题求助

问题分析与解决方案

核心问题原因

  1. 进程地址空间隔离:操作系统中每个进程都拥有独立的虚拟地址空间,全局变量globalInformation在不同进程中是完全独立的实例,内存地址自然不同。你看到的两个不同地址,是不同进程里这个全局变量本身的地址,而非字符串数据的地址。只有调用nativeMethod的进程会初始化自己的globalInformation,其他进程的该变量默认是NULL,这就是打印“Unable to access information value”的直接原因。
  2. 日志打印混淆:你的日志打印的是&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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 06:10:43