Java 如何从地址位置获取直接字节缓冲区

Java 如何从地址位置获取直接字节缓冲区,java,opencv,bytebuffer,unsafe,Java,Opencv,Bytebuffer,Unsafe,在中,Mat对象有一个nativeObj字段,返回表示对象地址的long(即140398889556640)。因为对象中数据的大小是已知的,所以我希望直接访问Mat对象的内容,返回一个字节缓冲区 这样做的最佳方式是什么?您可以使用DirectByteBuffer或使用不安全的方式包装地址 虽然你可以这样做,但你可能不应该这样做。我将首先探讨所有其他选择 // Warning: only do this if there is no better option public static voi

在中,Mat对象有一个
nativeObj
字段,返回表示对象地址的long(即
140398889556640
)。因为对象中数据的大小是已知的,所以我希望直接访问Mat对象的内容,返回一个字节缓冲区


这样做的最佳方式是什么?

您可以使用DirectByteBuffer或使用不安全的方式包装地址

虽然你可以这样做,但你可能不应该这样做。我将首先探讨所有其他选择

// Warning: only do this if there is no better option

public static void main(String[] args) {
    ByteBuffer bb = ByteBuffer.allocateDirect(128);
    long addr = ((DirectBuffer) bb).address();

    ByteBuffer bb2 = wrapAddress(addr, bb.capacity());

    bb.putLong(0, 0x12345678);
    System.out.println(Long.toHexString(bb2.getLong(0)));
}

static final Field address, capacity;
static {
    try {
        address = Buffer.class.getDeclaredField("address");
        address.setAccessible(true);
        capacity = Buffer.class.getDeclaredField("capacity");
        capacity.setAccessible(true);

    } catch (NoSuchFieldException e) {
        throw new AssertionError(e);
    }
}

public static ByteBuffer wrapAddress(long addr, int length) {
    ByteBuffer bb = ByteBuffer.allocateDirect(0).order(ByteOrder.nativeOrder());
    try {
        address.setLong(bb, addr);
        capacity.setInt(bb, length);
        bb.clear();
    } catch (IllegalAccessException e) {
        throw new AssertionError(e);
    }
    return bb;
}

您可以使用DirectByteBuffer包装地址,也可以使用不安全的

虽然你可以这样做,但你可能不应该这样做。我将首先探讨所有其他选择

// Warning: only do this if there is no better option

public static void main(String[] args) {
    ByteBuffer bb = ByteBuffer.allocateDirect(128);
    long addr = ((DirectBuffer) bb).address();

    ByteBuffer bb2 = wrapAddress(addr, bb.capacity());

    bb.putLong(0, 0x12345678);
    System.out.println(Long.toHexString(bb2.getLong(0)));
}

static final Field address, capacity;
static {
    try {
        address = Buffer.class.getDeclaredField("address");
        address.setAccessible(true);
        capacity = Buffer.class.getDeclaredField("capacity");
        capacity.setAccessible(true);

    } catch (NoSuchFieldException e) {
        throw new AssertionError(e);
    }
}

public static ByteBuffer wrapAddress(long addr, int length) {
    ByteBuffer bb = ByteBuffer.allocateDirect(0).order(ByteOrder.nativeOrder());
    try {
        address.setLong(bb, addr);
        capacity.setInt(bb, length);
        bb.clear();
    } catch (IllegalAccessException e) {
        throw new AssertionError(e);
    }
    return bb;
}

如果您不想使用不安全的
Unsafe
,并且希望在Java 9中可以无警告地工作,并且实际上可以跨JVM移植,那么您可以使用JNIs。这是API,保证可以工作


但是,您需要编写一些C(或C++)代码,并随代码一起提供一个本机库。

如果您不想使用不安全的
,并且想要在Java 9中工作而没有警告并且实际上可以跨JVM移植的东西,您可以使用JNIs。这是API,保证可以工作


不过,您需要编写一些C(或C++)代码,并随代码一起提供一个本机库。

有一个名为“nalloc”的小型框架,旨在帮助开发人员进行内存/指针操作,它可能对您寻找直接内存地址访问的任何用途都很有用

它还使您能够以C风格编写Java程序,手动处理内存


查看它:

有一个称为“nalloc”的小框架,旨在帮助开发人员进行内存/指针操作,它可以用于任何您想要直接访问内存地址的目的

它还使您能够以C风格编写Java程序,手动处理内存


检查它:

如果不知道可以安全访问多少,就无法访问内存。数据的大小不是未知的,它是mat.total()*mat.channels(),而不是
nativeObj
(它将指向
cv::mat
实例,而不是像素),似乎您想要
dataAddr
。查看源代码,它为您提供了指向像素数据的值
cv::Mat::data
。请记住,您还必须考虑数据不连续的情况(通常情况下,如果
Mat
代表较大图像的ROI)。@DanMašek。谢谢。如果不知道可以安全访问多少,您就无法访问内存。数据的大小不是未知的,它是mat.total()*mat.channels(),而不是
nativeObj
(它将指向
cv::mat
实例,而不是像素),看起来您需要
dataAddr
。查看源代码,它为您提供了指向像素数据的值
cv::Mat::data
。请记住,您还必须考虑数据不连续的情况(通常情况下,如果
Mat
代表较大图像的ROI)。@DanMašek。谢谢。你能给我一个如何包装地址的例子吗?@zcaudate我添加了一个简单的例子。顺便说一句,这不会在Java 9+上编译,但是你可以做类似的事情。你能给出一个如何包装地址的示例吗?@zcaudate我添加了一个简单的示例。顺便说一句,这不会在Java9+上编译,但您可以做类似的事情。