1

作为一个非常新手的 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);

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

4

3 回答 3

1

根据您提供的信息,您似乎正在使用不允许本机代码访问底层内存结构的 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

线程“主”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)
于 2010-12-26T16:43:22.417 回答
1

wrap 不会创建“直接”字节缓冲区。直接字节缓冲区通常由使用内存映射 API 产生。编写您正在使用的 JNI 代码的人对您并不友善,因为他们没有编写代码来容忍非直接缓冲区。

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

会做你需要的。

于 2010-12-26T17:27:41.047 回答
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();
于 2010-12-26T17:45:16.337 回答