通过JNI的NewDirectByteBuffer创建的缓冲区能否转为Java可访问的数组?
结论
通过NewDirectByteBuffer创建的是堆外直接缓冲区,本身不依托Java堆内的byte[]实现,无法直接让该ByteBuffer的array()方法返回有效Java数组,这是JDK的固定设计。
可选解决方案
你可以根据场景选择下面两种方案:
- 允许数据拷贝的场景
如果你可以接受一次内存拷贝,有两种实现方式:- Java侧自行拷贝:拿到DirectByteBuffer后直接读取内容到新的byte数组即可,代码示例:
ByteBuffer byteBuf = jniFunctionCall(); byte[] bytes = new byte[byteBuf.remaining()]; byteBuf.get(bytes);- JNI侧直接返回byte数组:不需要创建DirectByteBuffer,直接创建Java堆数组返回,代码示例:
jbyteArray jArray = jEnv->NewByteArray(len); jEnv->SetByteArrayRegion(jArray, 0, len, (const jbyte*)data); // 直接返回该jbyteArray对象到Java侧即可 - 不允许数据拷贝的场景
如果你要零拷贝操作原生内存,不需要转成byte[],直接调用ByteBuffer自带的get()、put()、读写偏移等API操作数据即可,所有功能和数组访问完全等价,性能没有差异。
注意事项
- 如果使用JNI直接返回byte数组的方案,原生内存的
data指针在调用SetByteArrayRegion完成后即可释放,内容已经拷贝到Java堆托管。 - 如果继续使用DirectByteBuffer方案,必须保证原生内存
data的生命周期长于Java侧持有该ByteBuffer的生命周期,否则会触发非法内存访问崩溃。
内容的提问来源于stack exchange,提问作者Pan Ruochen
相关产品推荐
相关产品推荐

