是什么导致“无法从 ByteBuffer 对象检索本机地址”?

发布于 2024-10-09 01:47:57 字数 510 浏览 1 评论 0原文

作为一个非常新手的 Java 程序员,我可能不应该搞乱这类事情。不幸的是,我使用的库有一个方法接受 ByteBuffer 对象,并在我尝试使用它时抛出:

Exception in thread "main" java.lang.NullPointerException: Unable to retrieve native address from ByteBuffer object

是因为我使用的是非直接缓冲区吗?

编辑: 我的代码并不多。我正在使用的库是 jNetPcap,我正在尝试将数据包转储到文件。我的代码获取一个现有数据包,并从中提取一个 ByteBuffer:

byte[] bytes = m_packet.getByteArray(0, m_packet.size());
ByteBuffer buffer = ByteBuffer.wrap(bytes);

然后它调用采用 ByteBuffer 的 jNetPcap 的转储方法。

As a very novice Java programmer, I probably should not mess with that kind of things. Unfortunately, I'm using a library which have a method that accepts a ByteBuffer object and throws when I try to use it:

Exception in thread "main" java.lang.NullPointerException: Unable to retrieve native address from ByteBuffer object

Is it because I'm using a non-direct buffer?

edit:
There's not a lot of my code there. The library I'm using is jNetPcap, and I'm trying to dump a packet to file. My code takes an existing packet, and extract a ByteBuffer out of it:

byte[] bytes = m_packet.getByteArray(0, m_packet.size());
ByteBuffer buffer = ByteBuffer.wrap(bytes);

Then it calls on of the dump methods of jNetPcap that takes a ByteBuffer.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

森罗 2024-10-16 01:47:57

许多 JNI 调用都需要直接的 ByteBuffer。即使 Oracle Java 6.0 中的标准库也期望这一点,如果您为它们提供堆 ByteBuffer,它们就会为您将数据复制到直接的 ByteBuffer 或从直接的 ByteBuffer 复制数据。在您的情况下,您有一个可以复制到直接 ByteBuffer 的 byte[] 。注意:创建直接 ByteBuffer 的成本很高,如果可以的话,您应该缓存/回收它们。

// the true size is always a multiple of a page anyway.
static final ByteBuffer buffer = ByteBuffer.allocateDirect(4096); 

// synchronize the buffer if you need to, or use a ThreadLocal buffer as a simple cache.
byte[] bytes = m_packet.getByteArray(0, m_packet.size());
buffer.clear();
buffer.put(bytes);
buffer.flip();

Many JNI calls expect a direct ByteBuffer. Even the standard libraries in Oracle Java 6.0 expect this and if you provide them with a heap ByteBuffer they copy your data to/from a direct one for you. In your case, you have a byte[] which can be copied to a direct ByteBuffer. note: creating a direct ByteBuffer is expensive and you should cache/recycle them if you can.

// the true size is always a multiple of a page anyway.
static final ByteBuffer buffer = ByteBuffer.allocateDirect(4096); 

// synchronize the buffer if you need to, or use a ThreadLocal buffer as a simple cache.
byte[] bytes = m_packet.getByteArray(0, m_packet.size());
buffer.clear();
buffer.put(bytes);
buffer.flip();
岁月染过的梦 2024-10-16 01:47:57

根据您提供的信息,您似乎正在使用 ByteBuffer 实现,该实现不允许本机代码访问底层内存结构。它试图访问 ByteBuffer 中的直接内存,这可能不应该这样做,并且失败,因为从 ByteBuffer 派生的类不直接存储数据。

如果这是您无法更改的关键代码,那么最好的选择是使用 Java 实现创建一个 ByteBuffer,然后将原始数据复制到临时缓冲区中;将新缓冲区传递给您的本机方法。然后我会分析代码以查看它是否对性能产生影响。

下面是如何执行此操作的示例。我对使用 rewind()limit() 有点犹豫,因为我不知道 ByteBuffer 的实现将返回什么,因此请检查以确保它实现ByteBuffer 的接口正确。

此代码故意非法访问索引 3,以表明未添加额外数据。

public static void main(String[] args) {

    // This will be your implementation of ByteBuffer that
    // doesn't allow direct access.
    ByteBuffer originalBuffer = ByteBuffer.wrap(new byte[]{12, 50, 70});


    originalBuffer.rewind();
    byte[] newArray = new byte[originalBuffer.limit()];
    originalBuffer.get(newArray, 0, newArray.length);

    ByteBuffer newBuffer = ByteBuffer.wrap(newArray);

    System.out.println("Limit: " + newBuffer.limit());
    System.out.println("Index 0: " + newBuffer.get(0));
    System.out.println("Index 1: " + newBuffer.get(1));
    System.out.println("Index 2: " + newBuffer.get(2));
    System.out.println("Index 3: " + newBuffer.get(3));
}

输出:

限制:3

索引 0: 12

索引 1: 50

索引 2: 70

线程“main”java 中出现异常。 lang.IndexOutOfBoundsException

    at java.nio.Buffer.checkIndex(Buffer.java:514)

    at java.nio.HeapByteBuffer.get(HeapByteBuffer.java:121)

    at stackoverflow_4534583.Main.main(Main.java:35)

Based on the information you've provided it appears you are using a ByteBuffer implementation that doesn't allow the Native code to get access to the underlying memory structure. It is attempting to access the direct memory in your ByteBuffer, which it probably shouldn't be doing, and is failing because the class deriving from ByteBuffer doesn't store data directly.

If this is critical code you can't change, your best bet would be to create a ByteBuffer using the Java implementation, then copy the original data into your temporary buffer; Pass the new buffer to your native method. I would then profile the code to see if it is a performance impact.

Here is an example of how to do this. I am a little hesitant to use rewind() and limit() as I don't know what the implementation of your ByteBuffer will return so check to make sure it implements the interface of ByteBuffer correctly.

This code illegally access index 3 on purpose to show that extra data isn't added.

public static void main(String[] args) {

    // This will be your implementation of ByteBuffer that
    // doesn't allow direct access.
    ByteBuffer originalBuffer = ByteBuffer.wrap(new byte[]{12, 50, 70});


    originalBuffer.rewind();
    byte[] newArray = new byte[originalBuffer.limit()];
    originalBuffer.get(newArray, 0, newArray.length);

    ByteBuffer newBuffer = ByteBuffer.wrap(newArray);

    System.out.println("Limit: " + newBuffer.limit());
    System.out.println("Index 0: " + newBuffer.get(0));
    System.out.println("Index 1: " + newBuffer.get(1));
    System.out.println("Index 2: " + newBuffer.get(2));
    System.out.println("Index 3: " + newBuffer.get(3));
}

Output:

Limit: 3

Index 0: 12

Index 1: 50

Index 2: 70

Exception in thread "main" java.lang.IndexOutOfBoundsException

    at java.nio.Buffer.checkIndex(Buffer.java:514)

    at java.nio.HeapByteBuffer.get(HeapByteBuffer.java:121)

    at stackoverflow_4534583.Main.main(Main.java:35)
墨离汐 2024-10-16 01:47:57

包装不会创建“直接”字节缓冲区。直接字节缓冲区通常是使用内存映射 API 产生的。无论谁编写您正在使用的 JNI 代码,都对您不友善,因为他们没有编写容忍非直接缓冲区的代码。

然而,一切并没有丢失: http: //download.oracle.com/javase/6/docs/api/java/nio/ByteBuffer.html#allocateDirect(int)

将满足您的需要。

wrap does not create a 'direct' byte buffer. A direct byte buffer typically results from using the memory mapping API. Whoever wrote the JNI code you are using wasn't kind to you insofar as they didn't write the code to tolerate a non-direct buffer.

However, all is not lost: http://download.oracle.com/javase/6/docs/api/java/nio/ByteBuffer.html#allocateDirect(int)

will do what you need.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文