问题
I am currently writing a small emulator in C++ using Java as a GUI. In order to achieve this I am making JNI calls from my C++ code passing arrays of data to the GUI application. However due to the shear amount of calls I made in a test run, it has become clear that in my function to pass data a memory leak is occurring.
Before my program has run:
After my program has run and crashed due to lack of memory: (Please ignore the CPU usage this program currently uses, I am aware that repeated calls through JNI is inefficient and I have other workarounds to this)
After thorough analysis of whats going on I have concluded that it is not the Java GUI class causing the memory leak but rather the code in the function that passes the data array to the Java GUI:
//java.env is the JNIEnv*
//setDisplay_ is a valid non-null jmethodID at runtime
//displayObject is a valid non-null jobject at runtime
void Display::setDisplay(vector<uint32_t>& a)
{
jint* buffer = new jint[a.size()];
for(int i = 0; i < a.size(); i++)
buffer[i] = (jint)a[i];
jintArray par = java.env->NewIntArray(a.size());
java.env->SetIntArrayRegion(par, 0, a.size(), buffer);
java.env->CallVoidMethod(displayObject, setDisplay_, par);
//java.env->ReleaseIntArrayElements(par, buffer, 0);
delete buffer;
}
The only thing I can see this function causing a memory leak over is the jintArray
which I have absolutely no idea what happens to when it goes out of scope so I can only assume is the issue as I release the buffer. However looking at sample code from other people using the JNI with arrays (ex: here) I notice that they never release the Array that they create. While digging through the JNI Documentation I came across the Release<NativeType>ArrayElements
Method which I assumed was what I was looking for due to the description:
ReleaseArrayElements Routines void ReleaseArrayElements(JNIEnv *env, ArrayType array, NativeType *elems, jint mode); A family of functions that informs the VM that the native code no longer needs access to elems. The elems argument is a pointer derived from array using the corresponding GetArrayElements() function. If necessary, this function copies back all changes made to elems to the original array. The mode argument provides information on how the array buffer should be released. mode has no effect if elems is not a copy of the elements in array. Otherwise, mode has the following impact, as shown in the following table:
The line that really gave me hope this was what i needed in particular was
The mode argument provides information on how the array buffer should be released
However upon further inspection, im not quite sure this is the method i orrignally thought it was, and this has proved itself in testing as well as it appears to call exit()
upon a failure (as JNI is so notorious for) and this failure occurs every time I run it with any of the Modes provided in the documentation.
So my Real Questions is:
When creating New<PrimitiveType>Array
from C++ code in JNI how do I release the <PrimitiveType>Array
's buffer?
回答1:
After a bit more digging I came upon Do I need to call ReleaseIntArrayElements on an array created with NewIntArray? with a short answer from @gerbit :
You have to release only reference:
jintArray pixels = env->NewIntArray(width * height); env->DeleteLocalRef(pixels)
So apparently when using the JNI in the direction of Java calling C++, you dont need to clean up your <PrimitiveType>Array
's as java handles this for you. However when calling from the direction of C++ to Java, You need to call DeleteLocalRef()
in order to prevent memory leaks.
来源:https://stackoverflow.com/questions/54264656/when-creating-newprimitivetypearray-from-c-code-in-jni-how-to-release-the-p