如何将本机内存复制到 DirectByteBuffer

Posted

技术标签:

【中文标题】如何将本机内存复制到 DirectByteBuffer【英文标题】:How to copy native memory to DirectByteBuffer 【发布时间】:2019-05-27 21:32:23 【问题描述】:

我知道一种方法 - 在 C++ 端使用 memcpy

C++方法:

void CopyData(void* buffer, int size)

    memcpy(buffer, source, size);

JNR 映射:

void CopyData(@Pinned @Out ByteBuffer byteBuffer, @Pinned @In int size);

Java 调用:

ByteBuffer buffer = ByteBuffer.allocateDirect(size);
adapter.CopyData(buffer, size);

但我想处理原生代码不复制数据,而只返回指向要复制的内存的指针的情况:

C++ 方法:

void* GetData1()

    return source;


// or

struct Data

    void* data;
;

void* GetData2(Data* outData)

    outData->data = source;

我知道如何编写 JNR 映射以便能够将数据复制到 HeapByteBuffer

Pointer GetData1();

// or

void GetData2(@Pinned @Out Data outData);

final class Data extends Struct 

    public final Struct.Pointer data;

    public DecodeResult(Runtime runtime) 
        super(runtime);

        data = new Struct.Pointer();
    

Java 调用:

ByteBuffer buffer = ByteBuffer.allocate(size);
Pointer dataPtr = adapter.GetData1();
dataPtr.get(0, buffer.array(), 0, buffer.array().length);

// or

ByteBuffer buffer = ByteBuffer.allocate(size);
Data outData = new Data(runtime);
adapter.GetData2(outData);

Pointer dataPtr = outData.data.get();
dataPtr.get(0, buffer.array(), 0, buffer.array().length);

但我还没有找到将内存复制到DirectByteBuffer 而不是HeapByteBuffer 的方法。上面的 sn-p 代码不适用于DirectByteBuffer,因为buffer.array() 对于这样的缓冲区为空,因为它由本机内存区域支持。

请帮忙。

【问题讨论】:

jnr-ffi 存储库中的单元测试表明,只有使用 memcpy 的方法是可能的:github.com/jnr/jnr-ffi/blob/master/src/test/java/jnr/ffi/… 【参考方案1】:

我找到了几种将 JNR 本机内存复制到 DirectByteBuffer 的方法。它们的效率不同。目前我使用以下方法,我不知道它是否是JNR作者最好的还是有意的:

ByteBuffer buffer = ByteBuffer.allocateDirect(size);
Pointer dataPtr = adapter.GetData1();
long destAddress = ((DirectBuffer)buffer).address();
Pointer destPtr = AsmRuntime.pointerValue(destAddress, runtime);

assert dataPtr.isDirect() && destPtr.isDirect();

dataPtr.transferTo(0, destPtr, 0, size);

ByteBuffer buffer = ByteBuffer.allocateDirect(size);
Data outData = new Data(runtime);
adapter.GetData2(outData);

Pointer dataPtr = outData.data.get();
long destAddress = ((DirectBuffer)buffer).address();
Pointer destPtr = AsmRuntime.pointerValue(destAddress, runtime);

assert dataPtr.isDirect() && destPtr.isDirect();

dataPtr.transferTo(0, destPtr, 0, size);

满足上面的断言子句很重要。它保证指针是jnr.ffi.provider.jffi.DirectMemoryIO 实例,并使用高效的memcpy 方法进行复制(检查DirectMemoryIO.transferTo() 的实现)。

另一种方法是使用以下方法包装DirectByteBuffer

Pointer destPtr = Pointer.wrap(runtime, destAddress);

Pointer destPtr = Pointer.wrap(runtime, destAddress, size);

但没有:

Pointer destPtr = Pointer.wrap(runtime, buffer);

第一个和第二个指针由DirectMemoryIO 支持,但第三个指针由ByteBufferMemoryIO 支持,它涉及缓慢的逐字节复制。

一个缺点是DirectMemoryIO 实例相当重量级。它在 JVM 堆上分配 32 个字节,因此在大量 JNR 调用的情况下,所有DirectMemoryIO 实例都会消耗很大一部分内存。

【讨论】:

以上是关于如何将本机内存复制到 DirectByteBuffer的主要内容,如果未能解决你的问题,请参考以下文章

如何将整数从 C# 方法复制到本机 C DLL 函数

将包含二进制文件的文件夹结构复制到本机库文件夹

如何远程复制另一台Linux服务器

文件怎么复制到虚拟机

如何把本机的文件复制到用mstsc命令远程登录的服务器

MobileFirst:将文件从本机资源文件夹复制到 Android 环境中的本机文件夹