如何将本机内存复制到DirectByteBuffer

时间:2019-05-27 21:32:24

标签: java c++ jnr

我知道一种方法-在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的方法。上面的代码段不适用于DirectByteBuffer,因为buffer.array()对于此类缓冲区为空,因为它由本机内存区域作为后援。

请帮助。

1 个答案:

答案 0 :(得分:2)

我发现了几种将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);

重要的是,必须满足上面的assert子句。它保证了指针是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(运行时,缓冲区);

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

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