使用JNI从C调用Java代码时内存泄漏(Memory leak when calling java

2019-07-03 21:13发布

我有一个存储使用JNI在Java软件商店某个对象的C程序。 (有人问之前,请使用Java软件商店是这里的要求及我必须写在C客户端,将能够从这个存储区中添加和检索对象)。

我制作的节目,并试图增加大小1KB 100000对象。 但仅增加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端临危在哈希表中的字节[]中的数据并将其存储。 问题是,每次代码运行内存仅增加了,并且永远不会释放。 我试图添加1个MB对象并调试它。

该过程内存1MB增加当我打电话NewByteArray。 但是,当CallStaticBooleanMethod被称为由4MB进程的内存增加。 并调用ReleaseByteArrayElements不会释放内存的。

如果我在这之后再添1MB的对象,然后当我打电话NewByteArray,它由1MB提升当我打电话CallStaticBooleanMethod但仍然是相同的,当我尝试释放字节数组进程的内存保持不变。

Answer 1:

当你调用新...功能,您可以创建一个“本地参考” - 引用此对象在本地堆栈帧。 这可以防止Java虚拟机从GC这个对象,而你仍然需要它。 这是好的,如果你正在实施一些本地方法 - 仅针对方法调用期间创建了本地帧。 但是,当你从一个本地Java的附着的丝线创建对象,它成为绑定到该线程的堆栈帧,这将只与此线程被破坏。

所以,当你有一个对象做,你可以调用DeleteLocalRef()来告诉你不再需要它。 或者你也可以围绕整个add()函数与对PushLocalFrame的()/ PopLocalFrame()来作出其持续时间单独的本地帧。



Answer 2:

功能ReleaseByteArrayElements和ReleaseStringUTFChars的目的不是要删除的对象,但后一个指针已经与GetByteArrayElements或GetStringUTFChars获得解锁。 两个if语句应该被删除。



Answer 3:

是的,我遇到了同样的问题。

我的Java应用程序中调用通过JNI C ++应用程序,在C ++应用程序将启动一个新的线程,并回调Java方法。 在新线程,创建了许多对象和内存迅速增加,虽然我用DeleteLocalRef,PushLocalFrame和PopLocalFram。

我发现,通过NewObject的方法创建不能释放许多对象。 真奇怪 。



Answer 4:

我试过了,大家说。

我们必须使用任何的jstring创建之后DeleteLocalRef方法并没有更多的用途。

Newxxx或CallStaticObjectMethod可能产生的jstring,这一切必须删除。



文章来源: Memory leak when calling java code from C using JNI