Включение заголовков C / C ++ с реализациями на Java для приложения Android - PullRequest
0 голосов
/ 20 января 2011

«Как я могу использовать большие статические массивы C или C ++ в Java?»

Я работаю с Android NDK и JNI, чтобы получить некоторый нативный код C (или C ++), работающий в Java.Это нормально, мой сгенерированный JNI-интерфейс и моя реализация на C (или C ++) работают.

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

Поэтому я бы хотел, чтобы этот массив не содержал заголовок Java и заголовок C или C ++ и имел егоготов в мире C или C ++ в любое время с момента загрузки приложения.Это критически важный компонент приложения.

Что я могу сделать?

Заранее благодарю.

//////////////////////////////////

Использование Get<PrimitiveType>ArrayElements от JNI - долгий путь к решению, единственное беспокойство - это выделение памяти.Вполне вероятно, что массив все-таки скопирован.

Но он работает в эмуляторе Android, и результаты впечатляют: вычисление, которое занимает 13 секунд в Java на эмуляторе, занимает 0,7 секунды на эмуляторе при его выполнении.в C.

Поскольку эмулятор Android довольно медленный, это, вероятно, подлинная цифра, единственный способ убедиться в этом - протестировать его на устройстве.

1 Ответ

1 голос
/ 21 января 2011

Взгляните на эту JNI Tips FAQ запись. Он может ответить на ваш вопрос или, по крайней мере, дать вам представление о доступных опциях.

ADDENDUM: (SK9) (Слишком большое поле для комментариев, извините) Соответствующая часть советов JNI приведена ниже. Следуя приведенным здесь указаниям, приложение будет аварийно завершать работу, если массив будет скопирован (что, безусловно, будет) из-за недостатка памяти.

///////////////////

Примитивные массивы

JNI предоставляет функции для доступа к содержимому объектов массива. В то время как массивы объектов должны быть доступны по одной записи за раз, массивы примитивов могут быть прочитаны и записаны напрямую, как если бы они были объявлены в C.

Чтобы сделать интерфейс максимально эффективным, не ограничивая реализацию виртуальной машины, семейство вызовов GetArrayElements позволяет виртуальной машине либо возвращать указатель на фактические элементы, либо выделять некоторую память и делать копию. В любом случае возвращаемый необработанный указатель гарантированно будет действительным до тех пор, пока не будет выполнен соответствующий вызов Release (что означает, что, если данные не были скопированы, объект массива будет закреплен и не может быть перемещен в рамках сжатия куча). Вы должны освободить каждый массив, который вы получаете. Кроме того, в случае сбоя вызова Get вы должны убедиться, что ваш код не пытается позднее освободить указатель NULL.

Вы можете определить, были ли данные скопированы, передавая ненулевой указатель для аргумента isCopy. Это редко полезно.

Вызов Release принимает аргумент режима, который может иметь одно из трех значений. Действия, выполняемые виртуальной машиной, зависят от того, вернула ли она указатель на фактические данные или их копию:

0 Фактически: объект массива не закреплен. Копировать: данные копируются обратно. Буфер с копией освобождается. JNI_COMMIT Фактически: ничего не делает. Копировать: данные копируются обратно. Буфер с копией не освобождается. JNI_ABORT Фактически: объект массива не закреплен. Ранее записи не прерываются. Копировать: буфер с копией освобождается; любые изменения в нем будут потеряны. Одна из причин проверки флага isCopy - узнать, нужно ли вам вызывать Release с JNI_COMMIT после внесения изменений в массив - если вы чередуетесь между внесением изменений и выполнением кода, использующего содержимое массива, вы можете пропустить неоперативный коммит. Другая возможная причина для проверки флага - для эффективной обработки JNI_ABORT. Например, вы можете получить массив, изменить его на месте, передать части другим функциям, а затем отменить изменения. Если вы знаете, что JNI делает новую копию для вас, нет необходимости создавать еще одну «редактируемую» копию. Если JNI передает вам оригинал, вам нужно сделать свою собственную копию.

Некоторые утверждают, что вы можете пропустить вызов Release, если * isCopy равен false. Это не вариант. Если буфер копирования не выделен, то исходная память должна быть закреплена и не может быть перемещена сборщиком мусора.

Также обратите внимание, что флаг JNI_COMMIT НЕ освобождает массив, и вам в конечном итоге потребуется снова вызвать Release с другим флагом. "

...