Используя sun.misc.Unsafe, какой самый быстрый способ сканировать байты из Direct ByteBuffer?

ПРЕДПОСЫЛКИ

Предположим, что у меня есть прямой ByteBuffer:

ByteBuffer directBuffer = ByteBuffer.allocateDirect(1024);

и предположим, что я передаю буфер в AsynchronousSocketChannel, чтобы читать фрагменты данных с этого сокета до X байтов за раз (1024 в примере здесь).

Время передачи сокета в direct ByteBuffer фантастично, потому что все это происходит в памяти собственной ОС; Я еще не прошел через барьер "мозгового мозга" JVM...

Вопрос

Предполагая, что моя задача - сканировать все байты, считанные в буфере прямого байта, для чего это самый быстрый способ сделать это?

Я изначально спросил "... используя sun.misc.Unsafe", но, возможно, это неправильное предположение.

ВОЗМОЖНЫЕ ПОДХОДЫ

В настоящее время я вижу три подхода, и мне больше всего интересно: №3:

  • (DEFAULT) Используйте ByteBuffer bulk-get, чтобы вытащить байты непосредственно из собственного пространства ОС во внутреннюю структуру байта [1024].
  • (UNSAFE) Используйте Unsafe getByte ops, чтобы вытащить значения непосредственно из ByteBuffer, пропустив все проверки границ стандарта ByteBuffer получить ops. Ответ Питера Лоури на здесь, казалось, предполагал, что эти исходные собственные методы в Unsafe даже могут быть оптимизированы компилятором JIT ( "intrinsics" ) для одиночных машинных инструкций, приводящих к еще большему фантастическое время доступа. (=== UPDATE === интересно, похоже, что базовый класс DirectByteBuffer делает именно это с get/put ops для заинтересованных. )
  • (BANANAS) В каком-то способе "преступление против человечества", используя Unsafe, могу ли я скопировать область памяти прямого ByteBuffer на тот же адрес памяти мой байт [1024] существует внутри виртуальной машины и просто начинает доступ к массиву с использованием стандартных индексов int? (Это делает предположение, что операция copyMemory может потенциально сделать что-то фантастически оптимизированное на уровне ОС.

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

Это отличается от "я могу использовать Unsafe для итерации по байту [] быстрее?" вопрос, поскольку я даже не планирую потянуть байты в byte [] внутренне, если нет необходимости.

Спасибо за время; просто любопытно, если кто-нибудь (Питер?) получил орехи с Unsafe, чтобы сделать что-то вроде этого.

Ответ 1

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

    byte[] bytes = new byte[N];
    for(int m=0; m<M; m++)
        for(int i=0; i<bytes.length; i++)
            sum += bytes[i];

    ByteBuffer bb = ByteBuffer.allocateDirect(N);
    for(int m=0; m<M; m++)
        for(int i=0; i<bb.remaining(); i++)
            sum += bb.get(i);

на моей машине разница составляет 0.67ns против 0.81ns (за цикл).

Я немного удивлен, что ByteBuffer не так быстро, как byte []. Но я думаю, что вы обязательно НЕ должны скопировать его в байт [], затем получите доступ.