使用sun.misc.Unsafe,从Direct ByteBuffer扫描字节的最快方法是什么?

Riy*_*lla 11 java performance bytebuffer unsafe

背景

假设我有一个直接的ByteBuffer:

ByteBuffer directBuffer = ByteBuffer.allocateDirect(1024);
Run Code Online (Sandbox Code Playgroud)

并假设我将缓冲区传递给AsynchronousSocketChannel以从该套接字读取数据块,一次最多X个字节(此处示例中为1024).

从套接字到直接 ByteBuffer 的传输时间非常棒,因为它全部发生在本机OS内存空间中; 我还没有通过JVM"血脑"屏障......

假设我的工作是扫描从直接字节缓冲区读回的所有字节,我这样做的最快方法是什么?

我最初问" ......利用sun.misc.Unsafe "但也许这是错误的假设.

可能的方法

我目前看到三种方法,我最感兴趣的是#3:

  1. (DEFAULT)使用ByteBuffer的bulk-get将字节从本机OS空间直接拉入内部字节[1024]结构.
  2. (UNSAFE)使用Unsafe的getByte操作直接从ByteBuffer中提取值,跳过ByteBuffer的标准get操作的所有边界检查.Peter Lawrey 在这里的答案似乎表明,Unsafe中的原始本机方法甚至可以通过JIT编译器("内在函数")优化为单机指令,从而实现更加出色的访问时间.(=== UPDATE ===有趣的是,看起来底层的DirectByteBuffer类与那些感兴趣的get/put操作完全相同.)
  3. (BANANAS)在一些犯罪与人类有关的方式中,使用Unsafe,我可以将直接ByteBuffer 的内存区域复制到我的字节[1024]存在于VM内部的相同内存地址,并开始访问数组使用标准的int索引?(这假设"copyMemory"操作可能会在操作系统级别进行奇妙优化.

我确实认为,假设copyMemory操作正是它所宣传的内容,即使在更优的操作系统空间中,上面的#2方法可能仍然是最优化的,因为我没有在开始处理之前创建缓冲区的重复项它.

这与" 我可以使用不安全迭代字节[]更快吗? "问题不同,因为我甚至没有计划在内部将字节拉入字节[],如果没有必要的话.

谢谢你的时间; 只是好奇,如果有人(彼得?)已经疯狂与不安全做这样的事情.

Zho*_*gYu 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);
Run Code Online (Sandbox Code Playgroud)

在我的机器上,差异是 0.67ns 与 0.81ns(每个循环)。

我有点惊讶 ByteBuffer 没有 byte[] 快。但我认为你绝对不应该将它复制到 byte[] 然后访问。