В настоящее время я пишу небольшой эмулятор на C ++, используя Java в качестве графического интерфейса. Чтобы добиться этого, я делаю вызовы JNI из моего кода C ++, передавая массивы данных в приложение с графическим интерфейсом. Однако из-за большого количества вызовов, которые я сделал в тестовом прогоне, стало ясно, что в моей функции передачи данных происходит утечка памяти.
До запуска моей программы:
![Before my program has run](https://i.stack.imgur.com/oH6GY.png)
После запуска и сбоя моей программы из-за нехватки памяти:
(Пожалуйста, не обращайте внимания на использование процессора этой программой в настоящее время, я знаю, что повторные вызовы через JNI неэффективны, и у меня есть другие обходные пути для этого)
После тщательного анализа происходящего я пришел к выводу, что утечка памяти вызывает не класс Java GUI, а код в функции, которая передает массив данных в GUI Java:
//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;
}
Единственное, что я могу видеть, что эта функция вызывает утечку памяти - это jintArray
, который я абсолютно не представляю, что происходит, когда она выходит из области видимости, поэтому я могу только предположить, что это проблема, когда я освобождаю буфер. Однако, глядя на пример кода от других людей, использующих JNI с массивами (например: здесь ), я замечаю, что они никогда не выпускают созданный ими массив. При копании в документации JNI я наткнулся на метод Release<NativeType>ArrayElements
, который, как я предполагал, был тем, что я искал, из-за описания:
Процедуры ReleaseArrayElements
void ReleaseArrayElements (JNIEnv * env,
Массив ArrayType, NativeType * elems, режим jint);
Семейство функций, которое сообщает виртуальной машине, что нативный код больше не нуждается в доступе к elems. Аргумент elems - это указатель, полученный из массива с использованием соответствующей функции GetArrayElements (). При необходимости эта функция копирует все изменения, сделанные в элементах, в исходный массив.
Аргумент mode предоставляет информацию о том, как должен быть освобожден буфер массива. Режим не действует, если elems не является копией элементов в массиве. В противном случае режим оказывает следующее влияние, как показано в следующей таблице:
Строка, которая действительно дала мне надежду, это было то, что мне было нужно, в частности, было
Аргумент mode предоставляет информацию о том, как должен быть освобожден буфер массива
Однако при дальнейшей проверке я не совсем уверен, что это метод, о котором я обычно думал, и он зарекомендовал себя при тестировании, а также, по-видимому, вызывает exit()
в случае сбоя (поскольку JNI так печально известен) и этот сбой происходит каждый раз, когда я запускаю его с любым из режимов, указанных в документации.
Итак, мои настоящие вопросы:
При создании New<PrimitiveType>Array
из кода C ++ в JNI, как освободить буфер <PrimitiveType>Array
?