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

11

背景

假设我有一个直接字节缓冲区:

ByteBuffer directBuffer = ByteBuffer.allocateDirect(1024);
假设我将缓冲区传递给AsynchronousSocketChannel,以从套接字读取数据块,每次读取X个字节(例如此处的1024个字节)。

将套接字中的数据转移到直接 ByteBuffer 中的传输时间非常快,因为它全部发生在本机操作系统内存空间中;我还没有穿过 JVM 的“血脑屏障”...

问题

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

我最初问了“...利用sun.misc.Unsafe”,但可能这是错误的假设。

可能的方法

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

  1. (默认) 使用ByteBuffer的bulk-get从本机操作系统空间直接拉取字节到内部byte[1024]结构中。
  2. (不安全) 使用Unsafe的getByte操作直接从ByteBuffer中提取值,跳过了ByteBuffer标准get操作的所有边界检查。Peter Lawrey在此处的答案似乎表明,这些 Unsafe 中的原始本机方法可以被 JIT 编译器(“内部函数”)优化为单个机器指令,从而导致更快速的访问时间。 (===更新===有趣的是,对于那些感兴趣的人,底层的DirectByteBuffer类正是使用这种方式进行get/put操作的。)
  3. (香蕉) 以某种违反人类罪行的方式,使用Unsafe,我可以将直接ByteBuffer的内存区域复制到VM中存在于byte[1024]相同内存地址上,并开始使用标准int索引访问该数组?(这使得“copyMemory”操作可以在 OS 级别上进行一些奇妙的优化假设。)

我想到了一个假设,即假设“copyMemory”操作确实做到了它所宣称的,即使在更优化的操作系统空间中,以上述第2种方法仍然是最优化的,因为我在开始处理它之前没有创建缓冲区的副本。

这与“我能否使用Unsafe更

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 vs 0.81ns。我有点惊讶ByteBuffer没有byte[]快。但我认为你绝对不应该将其复制到byte[]然后访问。

不知道 ByteBuffer 方法的“内在”属性;你是指特别是 DirectBuffer 类上的“本地”方法吗?如果是这样,那么它将完全做到我在上面帖子中提到的第二点,这是个好消息。 - Riyad Kalla
@RiyadKalla intrinsic != native。内置方法在JVM中是“硬编码”的。 - assylias
@assylias 我明白了;我(错误地)指的是 DirectByteBuffer impl 类上我认为是“本地”的方法(http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/nio/DirectByteBuffer.java),但现在我看一下,发现没有“本地”方法,它只是利用 Unsafe 来执行这些操作。我说错了,谢谢你的指正。 - Riyad Kalla
这是不安全的,它被视为内部机制,而不是ByteBuffer等。请参见https://github.com/airlift/slice,了解Java缓冲区的另一种替代且非常快速的实现。 - juancn
基准测试挑剔:你是否做了一些有用的事情(比如打印出)sum的值?否则JIT会将其优化掉。我认为每个循环0.67ns和0.81ns非常快,也许它确实是那么快,但我对此有点好奇。 - skiwi
@skiwi 当然,我已经打印出了“sum”。(虽然一个非常聪明的虚拟机可以自动推断出它是0 - ZhongYu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接