You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JIT预热后如何让ByteBuffer性能接近直接byte[]访问?

HeapByteBuffer性能低于自定义缓冲区的原因与优化疑问

优化简单解压缩例程时,发现一个奇怪的性能现象:手动实现的简易字节缓冲区,在单字节读取、多字节读取、判断流末尾这类简单操作上,比内置的HeapByteBuffer(堆内存及映射内存版本)快10%-20%。

测试的三种API

  • ByteBuffer.wrap(byte[]) 方法
  • 直接byte[]访问
  • 模仿ByteBuffer API实现的简易字节访问包装类方法

简易包装类实现

class TestBuf {
    private final byte[] ary;
    private int pos = 0;

    public TestBuf(ByteBuffer buffer) {  // 构造函数#1
        ary = new byte[buffer.remaining()];
        buffer.get(ary);
    }
    
    public TestBuf(byte[] inAry) { // 构造函数#2
        ary = inAry;
    }

    public int readUByte() { return ary[pos++] & 0xFF; }

    public boolean hasRemaining() { return pos < ary.length; }

    public void get(byte[] out, int offset, int length) {
        System.arraycopy(ary, pos, out, offset, length);
        pos += length;
    }
}

核心循环逻辑

while (buffer.hasRemaining()) {
    int op = buffer.readUByte();
    if (op == 1) {
        int size = buffer.readUByte();
        buffer.get(outputArray, outputPos, size);
        outputPos += size;
    } // ... 其他操作
}

测试组合

  • native-array:直接将byte[]传入接收byte[]的方法(无复制)
  • native-testbuf:将byte[]传入封装成TestBuf的方法(无复制,使用构造函数#2)
  • native-buffer:将ByteBuffer.wrap(byte[])传入接收ByteBuffer的方法(无复制)
  • buffer-array:将ByteBuffer.wrap(byte[])传入提取数组的方法
  • buffer-testbuf:将ByteBuffer.wrap(byte[])传入通过TestBuf构造函数#1提取数组的方法

测试环境与结果

使用JMH(对每个outputArray做黑盒测试),在OpenJDK和GraalVM的Java 17环境下测试,预加载约5GiB解压缩语料库(包含约150,000个2KiB到15MiB的文件),每个语料库解压缩约10秒,测试有充分预热和迭代。结果在多台电脑上波动但趋势一致:

  • GraalVM整体比OpenJDK慢10-15%,但性能排序一致
  • native-array和native-testbuf速度最快,误差在0.5%以内(每语料库9.3秒)
  • native-buffer始终最慢,比最快组合慢17-22%(每语料库11.4秒)
  • buffer-array和buffer-testbuf处于中间,比native-array慢4-7%(每语料库9.7秒),但比native-buffer快15-17%

关键疑问点

  1. 通过ByteBuffer API使用包装后的byte[](native-buffer),比自定义简易包装类(native-testbuf)慢很多
  2. 完整复制数组的组合(buffer-*),仍比使用ByteBuffer.wrap对象(native-buffer)快很多

希望解答:

  • 为何HeapByteBuffer在简单读取操作上比自定义实现慢?
  • 如何更高效地使用HeapByteBuffer?
  • 这种性能差异是否也适用于MappedByteBuffer?

更新

已发布完整基准测试、语料生成器和相关算法,近期发现删除无用代码或微调逻辑可让ByteBuffer性能接近原生数组,推测可能是偏移相关的内联缓存缺失导致。

内容的提问来源于stack exchange,提问作者byteit101

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 13:41:01