java - 使用 JNI 从 C 调用 java 代码时发生内存泄漏

标签 java c memory-leaks java-native-interface

我有一个 C 程序,它使用 JNI 在 java 存储中存储一些对象。 (在有人问之前,这里需要使用 java store,我必须用 C 编写一个客户端,它能够从这个 store 添加和检索对象)。

我编写了程序并尝试添加 100000 个大小为 1KB 的对象。但是在仅添加 50000 个对象后,我收到“内存不足”消息(请注意,每当我无法使用 NewStringUTF 和 NewByteArray 函数分配新的字符串或字节数组时,我都会打印这些“内存不足”消息)。那时我的应用程序只使用了 80MB 的内存。我不明白为什么这些方法返回 NULL。有什么我想念的吗。

此外,即使我正在释放为 java 创建的字节数组和字符串,内存也会继续增加。

这是源代码。

    void create_jvm(void)
{
    JavaVMInitArgs vm_args;     
    JavaVMOption vm_options;

    vm_options.optionString = "-Djava.class.path=c:\\Store";
    vm_args.version = JNI_VERSION_1_4;
    vm_args.nOptions = 1;
    vm_args.options = &vm_options;
    vm_args.ignoreUnrecognized = 0;

    JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);

    if(env != null)
    {
        j_store = (*env)->FindClass(env, "com/store");
        if(j_store == null)
        {
            printf("unable to find class. class name: JStore");
        }       
    }   
}

void add(char* key, char* value, int length)
{
    jstring j_key = (*env)->NewStringUTF(env, key);
    jbyteArray j_value = (*env)->NewByteArray(env, length);

    (*env)->SetByteArrayRegion(env, j_value, 0, length, (jbyte *)value);
    ret = (*env)->CallStaticBooleanMethod(env, j_store, method_id, j_key, j_value);

    if(j_value != null)
    {
        (*env)->ReleaseByteArrayElements(env, j_value, (jbyte *)value, 0);
    }
    if(j_key != null)
    {
        (*env)->ReleaseStringUTFChars(env, j_key, key);
    }
}

java端接收byte[]中的数据并将其存储在哈希表中。 问题是每次代码运行时,内存只会累加而永远不会释放。 我尝试添加 1 MB 对象并对其进行调试。

当我调用 NewByteArray 时,进程内存增加了 1MB。但是调用 CallStaticBooleanMethod 时进程内存增加了 4MB。调用 ReleaseByteArrayElements 根本不会释放任何内存。

如果我在此之后添加另一个 1MB 对象,那么当我调用 NewByteArray 时进程内存保持不变,当我调用 CallStaticBooleanMethod 时它增加 1MB 但当我尝试释放字节数组时它保持不变。

最佳答案

当您调用 New... 函数时,您会创建一个“本地引用” - 对本地堆栈框架中此对象的引用。这可以防止 Java VM 在您仍然需要该对象时对其进行 GC。如果您正在实现一些 native 方法,这很好 - 它的本地框架仅为方法调用持续时间创建。但是,当您从本地 java 附加线程创建对象时,它会绑定(bind)到此线程堆栈帧,该堆栈帧只会被此线程销毁。

因此,当您处理完某个对象后,您可以调用 DeleteLocalRef() 来告诉您不再需要它。或者,您可以用一对 P​​ushLocalFrame()/PopLocalFrame() 包围整个 add() 函数,以在其持续时间内创建一个单独的本地框架。

关于java - 使用 JNI 从 C 调用 java 代码时发生内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1340938/

相关文章:

java - 单例中的线程安全

java - 我什么时候应该在 PriorityQueue 上使用 TreeMap,反之亦然?

c - 如何使用 bios 中断打印字符串

c - C程序中用于检查字符大小写的 bool 错误

c++ - 使用 typeinfo::name() 后内存泄漏

java - 将 CharBuffer 转换为 ByteBuffer

java - 如何在 Android 的 TextView 中随机设置文本?

c - 为什么open在这个循环中返回null? C

ruby-on-rails - 超过 RAM 时重新启动 heroku dynos

memory-leaks - 如何修复 CFXURLCache 和 _NSURLSessionLocal 之间的保留周期?