Использовать JNI или не использовать JNI (производительность Android) - PullRequest
10 голосов
/ 27 января 2012

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

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

Я рассматривал различные способы оптимизации этого кода, и мне интересно, перемещать ли кодв C ++ и доступ к нему с помощью JNI, если я получу заметное снижение производительности?

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

  • Это сделает код чище.Поскольку большая часть обнаружения столкновений является своего рода векторной математикой, гораздо удобнее использовать перегруженные операторы, чем использовать более подробные векторные классы в Java.

  • Управление памятью будетбудь проще.Проще сказать?Что ж, это игра, поэтому запуск сборщика мусора нежелателен, поскольку сборщик мусора может в конечном итоге испортить производительность вашей игры, если ему постоянно приходится прерывать работу для очистки.В CI не нужно беспокоиться о сборщике мусора, поэтому я могу избежать всех отвратительных вещей, которые я делаю в Java с временными статическими переменными, и просто положиться на старую старую память C ++

Как ни крути вопрос, думаю, я рассмотрел все свои вопросы.Учитывая эту информацию, стоило бы переносить мой код с Java на C ++ и обращаться к нему с помощью JNI (по соображениям повышения производительности)?Кроме того, есть ли способ измерить или оценить потенциальное увеличение производительности?

РЕДАКТИРОВАТЬ:

Итак, я сделал это.Результаты?Что ж, с точки зрения TraceView, скорость моей процедуры обнаружения столкновений увеличилась в 6 раз.

Хотя добраться туда было нелегко.Помимо необходимости танцевать JNI, я также должен был сделать некоторые оптимизации, которые я не ожидал.Главным образом, использование непосредственно выделенного плавающего буфера для передачи данных из Java в native.Моя первоначальная попытка просто использовала массив float для хранения данных, потому что преобразование из Java в C ++ было более естественным, но это было действительно очень медленно.Прямой буфер полностью обошел проблемы с производительностью при копировании массива между java и native, и у меня остался 6-кратный удар.

Кроме того, вместо того, чтобы использовать свой собственный векторный класс, я просто использовал библиотеку математики Эйгена.Я не уверен, насколько это повлияло на производительность, но, по крайней мере, это сэкономило мне время на разработку моего собственного (менее эффективного) векторного класса.

Еще один урок заключается в том, чточрезмерное ведение журнала отрицательно сказывается на производительности (это не очевидно).

Ответы [ 2 ]

4 голосов
/ 27 января 2012

Не совсем прямой ответ на ваш вопрос, но вам могут пригодиться следующие ссылки:

Во второй ссылке написано следующее:

Собственный код не обязательно более эффективен, чем Java.С одной стороны, с переходом на нативную версию Java связаны затраты, и JIT не может оптимизировать через эти границы.Если вы выделяете собственные ресурсы (память в собственной куче, файловые дескрипторы и т. Д.), Может быть значительно сложнее организовать своевременный сбор этих ресурсов.Вам также необходимо скомпилировать код для каждой архитектуры, на которой вы хотите работать (а не полагаться на то, что у нее есть JIT).Возможно, вам даже придется скомпилировать несколько версий для одной и той же архитектуры: собственный код, скомпилированный для процессора ARM в G1, не может в полной мере использовать ARM в Nexus One, и код, скомпилированный для ARM в Nexus One.не будет работать на ARM в G1.

Собственный код в первую очередь полезен, когда у вас есть собственная базовая кодовая база, которую вы хотите перенести на Android, а не для «ускорения» частей Java-приложения.

1 голос
/ 01 февраля 2012

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

...