使用 JNI 从 C 调用 java 代码时出现内存泄漏 [英] Memory leak when calling java code from C using JNI

查看:68
本文介绍了使用 JNI 从 C 调用 java 代码时出现内存泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a C program that stores some object in java store using JNI. (Before someone ask, using java store is a requirment here and I have to write a client in C which would be able to add and retrieve objects from this store).

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

I made the program and tried to add 100000 object of size 1KB. But after adding only 50000 objects I am getting 'out of memory' messages (please note that I am printing these 'out of memory' messages whenever I am unable to allocate a new string or byte array using NewStringUTF and NewByteArray functions). At that time my application is using only 80MB of memory. I dont why these methods are returning NULL. Is there something I am missing.

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

Furthermore, the memory keeps on increasing even though I am releasing byte array and string created for 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 对象并对其进行调试.

The java side recieves the data in byte[] and stores it in a hashtable. The issue is that everytime the code runs the memory only adds up and is never released. I tried to add 1 MB object and debugged it.

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

The process memory increases by 1MB when I call NewByteArray. But when CallStaticBooleanMethod is called the process memory increase by 4MB. And the call to ReleaseByteArrayElements do not release any memory at all.

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

If I add another 1MB object after this, then process memory remains same when I call NewByteArray and it increase by 1MB when I call CallStaticBooleanMethod but remains the same when I try to release the byte array.

推荐答案

当你调用 New... 函数时,你创建了一个本地引用"——在本地堆栈帧中引用这个对象.这可以防止 Java VM 在您仍然需要此对象时对其进行 GC.如果您正在实现一些本机方法,这很好 - 它的本地框架仅在方法调用持续时间内创建.但是当你从一个原生的 java 附加线程创建对象时,它会绑定到这个线程堆栈帧,只有这个线程才会销毁它.

When you call New... functions, you create a "local reference" - reference to this object in local stack frame. This prevents Java VM from GC this object while you still need it. This is fine if you are implementing some native method - its local frame is created only for method call duration. But when you are creating object from a native java-attached thread, it becomes bound to this thread stack frame, which will be destroyed only with this thread.

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

So, when you done with an object you can call DeleteLocalRef() to tell you no longer need it. Or you can surround the whole add() function with pair of PushLocalFrame()/PopLocalFrame() to make a separate local frame for its duration.

这篇关于使用 JNI 从 C 调用 java 代码时出现内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆