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

时间:2013-08-13 22:40:18

标签: java performance unsafe bytebuffer

背景

假设我有一个直接的ByteBuffer:

ByteBuffer directBuffer = ByteBuffer.allocateDirect(1024);

并假设我将缓冲区传递给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的回答here似乎表明,不安全的原始本机方法甚至可以通过JIT编译器(“内在函数”)优化为单机指令,从而实现更加出色的访问时间。 (=== UPDATE ===有趣的是,对于那些感兴趣的人来说,底层的 DirectByteBuffer 类看起来与get/put ops完全相同。)
  3. (BANANAS)在一些犯罪 - 反人类的方式中,使用Unsafe,我可以copy the memory region将直接ByteBuffer连接到同一个内存地址,我的字节[1024]存在于VM的内部,并且只是使用标准的int索引开始访问数组? (这假设“copyMemory”操作可能会在操作系统级别上做一些极好的优化。
  4. 我确实认为,假设 copyMemory 操作完全正如它所宣传的那样,即使在更优化的操作系统空间中,上面的#2方法可能仍然是最优化的,因为我是在开始处理缓冲区之前不要创建缓冲区的重复项。

    这与“can I use Unsafe to iterate over a byte[] faster?”问题不同,因为如果没有必要,我甚至不打算在内部将字节拉入byte []。

    感谢您的时间;只是好奇,如果有人(彼得?)已经疯了,不安全做这样的事情。

1 个答案:

答案 0 :(得分: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 vs 0.81ns(每个循环)。

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