11

背景

假设我有一个直接的 ByteBuffer:

ByteBuffer directBuffer = ByteBuffer.allocateDirect(1024);

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

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

问题

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

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

可能的方法

我目前看到三种方法,我最好奇的是#3:

  1. (默认)使用 ByteBuffer 的bulk-get将字节直接从本机 OS 空间提取到内部 byte[1024] 构造中。
  2. (不安全)使用 Unsafe 的getByte操作将值直接从 ByteBuffer 中提取出来,从而跳过 ByteBuffer 的标准 get 操作的所有边界检查。Peter Lawrey在这里的回答似乎表明 Unsafe 中的那些原始本机方法甚至可以通过 JIT 编译器(“内在”)优化为单个机器指令,从而获得更出色的访问时间。(===UPDATE=== 有趣,看起来底层的DirectByteBuffer类对感兴趣的人使用get/put 操作正是这样做的。)
  3. (香蕉)以某种反人类犯罪的方式,使用 Unsafe,我可以将直接 ByteBuffer的内存区域复制到我的 byte[1024] 存在于 VM 内部的相同内存地址,然后开始访问数组使用标准的 int 索引?(这假设“copyMemory”操作可能会在操作系统级别做一些非常优化的事情。

我确实想到,假设copyMemory操作完全符合它所宣传的,即使在更优化的操作系统空间中,上面的#2 方法可能仍然是最优化的,因为我没有在开始处理之前创建缓冲区的副本它。

这与“我可以使用 Unsafe 更快地迭代 byte[] 吗? ”问题不同,因为如果没有必要,我什至不打算在内部将字节拉入 byte[]。

感谢您的时间;只是好奇是否有人(彼得?)对 Unsafe 做这样的事情发疯了。

4

1 回答 1

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[] 快。但我认为你绝对不应该将它复制到一个 byte[] 然后访问。

于 2013-08-14T00:19:07.357 回答