При создании New <PrimitiveType>Array из кода C ++ в JNI, как освободить буфер <PrimitiveType>Array? - PullRequest
0 голосов
/ 19 января 2019

В настоящее время я пишу небольшой эмулятор на C ++, используя Java в качестве графического интерфейса. Чтобы добиться этого, я делаю вызовы JNI из моего кода C ++, передавая массивы данных в приложение с графическим интерфейсом. Однако из-за большого количества вызовов, которые я сделал в тестовом прогоне, стало ясно, что в моей функции передачи данных происходит утечка памяти.

До запуска моей программы: Before my program has run

После запуска и сбоя моей программы из-за нехватки памяти: enter image description here (Пожалуйста, не обращайте внимания на использование процессора этой программой в настоящее время, я знаю, что повторные вызовы через 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?

1 Ответ

0 голосов
/ 19 января 2019

После еще нескольких копаний я наткнулся на Нужно ли вызывать ReleaseIntArrayElements для массива, созданного с помощью NewIntArray? с кратким ответом от @gerbit:

Вы должныссылка только для релиза:

jintArray pixels = env->NewIntArray(width * height);
env->DeleteLocalRef(pixels)

Так что, очевидно, при использовании JNI в направлении Java, вызывающего C ++, вам не нужно очищать свои <PrimitiveType>Array, поскольку Java обрабатывает это для вас.Однако при вызове из направления C ++ в Java вам необходимо вызвать DeleteLocalRef(), чтобы предотвратить утечки памяти.

...