作为一名非常新手的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的转储方法。
答案 0 :(得分:1)
根据您提供的信息,您似乎正在使用ByteBuffer实现,该实现不允许Native代码访问底层内存结构。它试图访问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)
答案 1 :(得分:1)
wrap不会创建“直接”字节缓冲区。直接字节缓冲区通常来自使用内存映射API。编写您正在使用的JNI代码的人并不善待您,因为他们没有编写代码来容忍非直接缓冲区。
然而,一切都没有丢失:http://download.oracle.com/javase/6/docs/api/java/nio/ByteBuffer.html#allocateDirect(int)
会做你需要的。
答案 2 :(得分:1)
许多JNI调用都期望直接使用ByteBuffer。即使是Oracle Java 6.0中的标准库也希望如此,如果您为它们提供堆ByteBuffer,它们会为您直接复制数据。在您的情况下,您有一个byte []可以复制到直接的ByteBuffer。注意:创建一个直接的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();