JNI EnsureLocalCapacity - ПОЧЕМУ? - PullRequest
9 голосов
/ 16 августа 2011

Посмотрите документы JNI здесь: http://download.oracle.com/javase/1.5.0/docs/guide/jni/spec/functions.html

В частности, посмотрите, что сказано в описании для функции EnsureLocalCapacity:

Для обратной совместимости ВМ выделяет локальные ссылки за пределы Обеспеченная мощность. (В качестве поддержки отладки виртуальная машина может дать предупреждения пользователей о том, что создается слишком много локальных ссылок. в JDK, программист может предоставить параметр командной строки -verbose: jni для включите эти сообщения.) VM вызывает FatalError, если не более локально ссылки могут быть созданы за пределами гарантированной емкости.

И, кроме того, посмотрите, как PushLocalFrame принимает аргумент «емкость». (И, кстати, здесь не упоминается, является ли это жестким или мягким ограничением, как в случае EnsureLocalCapacity).

Откуда вообще вся эта ерунда о местной эталонной мощности? В документах говорится, что виртуальная машина будет хотеть распределять ссылки за пределы текущей официальной емкости, так почему бы просто не сделать это и не допустить, чтобы весь этот беспорядок емкости оставался за пределами API?

Чтобы провести аналогию с C, мне кажется, что меня просят заранее спланировать, сколько вызовов malloc () я собираюсь сделать, и это выглядит немного смешно.

Есть что-то важное, чего я просто не вижу здесь?

Ответы [ 3 ]

0 голосов
/ 31 января 2016

Насколько я понимаю, размер локальной справочной таблицы предопределен, и если вы выделите больше, он просто потерпит крах.Так что это не значит, что VM будет давать вам больше локальных ссылок навсегда.Я сталкивался с этим много раз, работая с JNI на Android.Часто бывает трудно найти такую ​​утечку памяти.И вызов env-> DeleteLocalRef () каждый раз, когда вы что-то делаете с локальными ссылками JNI, просто загромождает код.Поэтому вместо того, чтобы загромождать код вызовами DeleteLocalRef (), мы можем просто убедиться, что мы не создаем слишком много ссылок и сохраняем код достаточно чистым.И даже если мы планируем выделить гораздо больше локальных ссылок, мы все равно можем просто вызвать PushLocalFrame () / PopLocalFrame () и избежать многих вызовов DeleteLocalRef ().

Итак, чтобы дать вам аналогию с «C», выпросят заранее спланировать ваши звонки в malloc, чтобы в конце избежать всех необходимых звонков на free ().

0 голосов
/ 01 марта 2017

Документация JNI по этому вопросу мягкая.Я обнаружил на практике, что иногда количество локальных ссылок кажется неограниченным, но вы действительно можете исчерпать локальные ссылки, например, при переборе массива с использованием вызовов JNI.Что такое местная ссылка?Это рабочий объект (или jarray, jstring и т. Д.), Который вы получаете из любого из следующих источников:

  • Возвращается из необработанного вызова JNI, такого как NewObjectV () или GetObjectArrayElement ()
  • Возвращено из вызова метода, такого как CallObjectMethodV ()
  • Передано в вашу нативную функцию в качестве аргумента
  • Вероятно, другие, которые я забыл

Из них вам обычно нужноне беспокойтесь о ссылках, которые передаются вам в аргументе метода, ЕСЛИ вы не намерены хранить ссылку за пределами текущего вызова метода, и в этом случае вы должны преобразовать ее в глобальную.

Стоит отметить, чтоВы не должны висеть на локальной ссылке за пределами текущей области метода.Если вы собираетесь хранить его в объекте C ++, вы должны преобразовать его в глобальный.Локальные ссылки имеют два преимущества:

  1. Они всегда освобождаются автоматически, когда текущий кадр выходит из области видимости.
  2. Они быстрее, чем конвертируются в глобальные

Как и большинство ошибок JNI, любое неправильное использование ссылок ужасно диагностировать, поэтому вы действительно не хотите их получать.Ваша лучшая защита - последовательный подход.По моему опыту, стоимость преобразования локального в глобальный довольно мала.Я бы предложил следующее, если только у вас нет очень строгих требований к производительности.
Учитывая это, мое правило - ВСЕГДА преобразовывать локальные ссылки в глобальные ссылки, используя такой код:

jobject localjo = ...
jobject globaljo = env->NewGlobalRef(localjo);
env->DeleteLocalRef(localjo);

На этом этапевы можете знать, что каждый ref является глобальным, и когда вы закончите, вам нужно помнить, что нужно выполнить env-> DeleteGlobalRef (globaljo) для каждого.В C ++ можно написать класс-оболочку вокруг ссылок JNI, который вызывает env-> DeleteGlobalRef () в dtor.Но так как JNI не подсчитывает ссылки JNI для вас, вам, возможно, потребуется встроить это.

0 голосов
/ 28 февраля 2012

Это моя догадка .Я подозреваю, что наращивание локальной эталонной емкости обходится дорого, и эта функция позволяет запрашивать нужную емкость один раз за вызов собственного метода.Я думаю, что это больше о производительности, чем о правильности.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...