通过 java API 并使用 malloc 创建缓冲区将字符串处理到 JNI 层

Processing a string into JNI layer by passing through java API and creating a buffer using malloc

我正在研究 java API,它将用于处理 cpp 中的字符串和 return 已处理的字符串。

我使用的jni中的cpp代码如下所述

char * buffer;
static
void process(char *str, int shift) {
    // some processing 
}
extern "C" JNIEXPORT jstring JNICALL Java_com_example_process (
        JNIEnv *env,
        jobject,
        jstring string,
        jint shift) {
    const char *key = env->GetStringUTFChars(string, nullptr);
    buffer = (char *)malloc(sizeof(key));

    strcpy(buffer, key);

    char *p = buffer;
    process(buffer, shift);

    env->ReleaseStringUTFChars(string, key);
    return env->NewStringUTF(p);

}
extern "C" JNIEXPORT void JNICALL Java_com_example_freeN (
        JNIEnv *env,
        jobject) {
    free(buffer);
    buffer = nullptr;
}

Java API

fun processStr(string: String): String {

            val str = process(string, 10)
            freeN()
            return str
        }

这里有几点需要注意:

1. 由于使用 JNI 从 java 传递给 C 的字符串,它作为 const 接收,我无法进行任何操作,因此创建并使用缓冲区strcpy 复制然后操作字符串

2. 从 java 代码本身调用 freeN() 以释放分配的缓冲区。

3. 可能还有另一种方法,从 java 传递 java 的 ByteBuffer,然后在 JNI 中使用缓冲区 这种方式不会释放内存有问题吗?

这些是解决这个问题的正确方法吗?有什么更好的方法?我怎样才能使它线程安全? 你认为异步调用 java API 是个好主意还是 API 应该同步?

我无法从你的问题中弄清楚 process 是否依赖于它的输入以 null 终止,但请注意,这不是规范所要求的。我也不知道 process' 输入和输出的形状应该是什么。如果你要传入或传出任意数据,那应该是 Java byte[]ByteBuffer 而不是 java.lang.String .

env->NewStringUTF(p) 分配一个新的 Java 字符串,其内存由 Java.
管理 一旦分配了字符串,您就可以安全地释放 buffer.

其次,通过全局存储 buffer,您使您的函数不可重入,并且让您的生活更加艰难。想象一下如果两个线程同时调用 Java_com_example_process 会发生什么。

最后,sizeof(key) returns 指针 的大小,而不是它指向的东西。因此,如果您的字符串超过 4 或 8 个字节(取决于体系结构),这将严重失败。幸运的是,您可以简单地询问 JNI 您的字符串长度是多少。

我建议进行以下重写,其中 JVM 负责处理返回的字符串,因此您不必再调用 freeN

static void process(const char *in, char *out, int shift) {
    // some processing where you take data from `in` and write to `out`
}

extern "C" JNIEXPORT jstring JNICALL Java_com_example_process (
        JNIEnv *env,
        jobject,
        jstring string,
        jint shift) {
    jsize key_size = env->GetStringUTFLength(string);
    const char *key = env->GetStringUTFChars(string, nullptr);

    char * buffer = new char[key_size];
    process(key, buffer, shift);

    env->ReleaseStringUTFChars(string, key);
    jstring ret = env->NewStringUTF(buffer);
    delete[] buffer;

    return ret;
}