Что вызывает «Невозможно получить собственный адрес из объекта ByteBuffer»? - PullRequest
1 голос
/ 26 декабря 2010

Как очень начинающий программист на 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.

Ответы [ 3 ]

1 голос
/ 26 декабря 2010

wrap не создает прямой байтовый буфер. Прямой байтовый буфер обычно получается в результате использования API отображения памяти. Кто бы ни писал код JNI, который вы используете, он не был добр к вам, поскольку он не писал код, чтобы допустить непрямой буфер.

Однако еще не все потеряно: http://download.oracle.com/javase/6/docs/api/java/nio/ByteBuffer.html#allocateDirect(int)

сделает то, что вам нужно.

1 голос
/ 26 декабря 2010

Многие вызовы JNI ожидают прямого байтового буфера.Даже стандартные библиотеки в Oracle Java 6.0 ожидают этого, и если вы предоставите им кучу ByteBuffer, они скопируют ваши данные в / из прямого для вас.В вашем случае у вас есть байт [], который можно скопировать в прямой 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();
1 голос
/ 26 декабря 2010

Судя по предоставленной вами информации, вы используете реализацию ByteBuffer, которая не позволяет нативному коду получить доступ к базовой структуре памяти.Он пытается получить доступ к прямой памяти в вашем ByteBuffer, чего он, вероятно, не должен делать, и терпит неудачу, потому что класс, производный от ByteBuffer, не хранит данные напрямую.

Если это критический код, который вы не можете изменить, лучше всего было бы создать ByteBuffer с использованием реализации Java, а затем скопировать исходные данные во временный буфер;Передайте новый буфер вашему собственному методу.Затем я бы профилировал код, чтобы увидеть, влияет ли это на производительность.

Вот пример того, как это сделать.Я немного не решаюсь использовать 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)
...