是什么导致“无法从 ByteBuffer 对象检索本机地址”?
作为一个非常新手的 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 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
许多 JNI 调用都需要直接的 ByteBuffer。即使 Oracle Java 6.0 中的标准库也期望这一点,如果您为它们提供堆 ByteBuffer,它们就会为您将数据复制到直接的 ByteBuffer 或从直接的 ByteBuffer 复制数据。在您的情况下,您有一个可以复制到直接 ByteBuffer 的 byte[] 。注意:创建直接 ByteBuffer 的成本很高,如果可以的话,您应该缓存/回收它们。
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.
根据您提供的信息,您似乎正在使用 ByteBuffer 实现,该实现不允许本机代码访问底层内存结构。它试图访问 ByteBuffer 中的直接内存,这可能不应该这样做,并且失败,因为从 ByteBuffer 派生的类不直接存储数据。
如果这是您无法更改的关键代码,那么最好的选择是使用 Java 实现创建一个 ByteBuffer,然后将原始数据复制到临时缓冲区中;将新缓冲区传递给您的本机方法。然后我会分析代码以查看它是否对性能产生影响。
下面是如何执行此操作的示例。我对使用
rewind()
和limit()
有点犹豫,因为我不知道 ByteBuffer 的实现将返回什么,因此请检查以确保它实现ByteBuffer 的接口正确。此代码故意非法访问索引 3,以表明未添加额外数据。
public static void main(String[] args) {
输出:
限制:3
索引 0: 12
索引 1: 50
索引 2: 70
线程“main”java 中出现异常。 lang.IndexOutOfBoundsException
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()
andlimit()
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) {
Output:
Limit: 3
Index 0: 12
Index 1: 50
Index 2: 70
Exception in thread "main" java.lang.IndexOutOfBoundsException
包装不会创建“直接”字节缓冲区。直接字节缓冲区通常是使用内存映射 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.