Вам нужно только /dev/ashmem
, чтобы разделить память между процессами. NDK и SDK (Java / Kotlin) работают в одном и том же Linux процессе и имеют полный доступ к одному и тому же пространству памяти.
Обычный способ определения памяти, который можно использовать как из C ++, так и Java, - это путем создания Direct ByteBuffer. Для этого вам не нужен JNI, Java API имеет ByteBuffer.allocateDirect (intacity) . Если для вашего логического потока более естественно выделить буфер на стороне C ++, JNI имеет функцию NewDirectByteBuffer (JNIEnv * env, void * address, jlong емкость) , которую вы использовали в своем вопросе.
Работать с Direct ByteBuffer очень легко на стороне C ++, но не так эффективно на стороне JVM. Причина в том, что этот буфер не поддерживается массивом, и единственный API, который у вас есть, включает ByteBuffer.get () с типизированными вариациями (получение байтового массива, char, int,…). Вы управляете текущей позицией в буфере, но работа таким образом требует определенной дисциплины: каждая операция get () обновляет текущую позицию. Кроме того, произвольный доступ к этому буферу довольно медленный, потому что он включает в себя вызов API позиционирования и получения. Поэтому в некоторых случаях нетривиальных структур данных может быть проще написать свой код пользовательского доступа на C ++ и иметь «интеллектуальные» методы получения, вызываемые через JNI.
Важно не забыть установить ByteBuffer.order (ByteOrder.nativeOrder ()) . Порядок вновь созданного байтового буфера нелогично BIG_ENDIAN. Это относится как к буферу, созданному из Java, так и из C ++.
Если вы можете изолировать случаи, когда C ++ нужен доступ к такой общей памяти, и вам не нужно постоянно его закреплять, это Стоит рассмотреть работу с байтовым массивом. В Java у вас есть более эффективный произвольный доступ. На стороне NDK вы будете вызывать GetByteArrayElements () или GetPrimitiveArrayCritical () . Последний более эффективен, но его использование накладывает ограничения на то, какие функции Java можно вызывать до освобождения массива. На Android оба метода не включают выделение и копирование памяти (однако, без официальной гарантии). Даже если сторона C ++ использует ту же память, что и Java, ваш код JNI должен вызывать соответствующую функцию Release… (), и лучше сделать это как можно раньше. Это хорошая практика для обработки этого Get / Release через RAII.