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

Netty4优化:将ByteBuf指定字节直接复制到Native Direct ByteBuffer

Netty 4 直接将ByteBuf数据写入Native Direct ByteBuffer的优化方案

核心优化思路

跳过堆ByteBuffer中转环节,直接在Netty的ByteBuf与目标Native Direct ByteBuffer之间完成内存拷贝,利用Netty原生API或底层内存操作实现高效数据传输。

方案一:通过Buffer边界控制+Netty原生API实现直接写入

你之前调用readBytes(bb)触发异常,本质是未正确设置Direct ByteBuffer的读写边界。只需先限定目标缓冲区的写入范围,再调用Netty的readBytes(ByteBuffer)方法即可:

try {
    receivingBuf.writeBytes((ByteBuf) msg);

    if (receivingBuf.readableBytes() >= nextPacketLength) {
        // 修改ByteBufferPoolManager,使其返回Native Direct ByteBuffer(而非堆ByteBuffer)
        ByteBuffer directBb = ByteBufferPoolManager.getDirectByteBuffer();
        int targetLength = nextPacketLength - 12;
        
        // 限定Direct ByteBuffer的写入边界
        directBb.position(0);
        directBb.limit(targetLength);
        // 直接从ByteBuf写入指定长度的数据到Direct ByteBuffer
        receivingBuf.readBytes(directBb);
        // 重置缓冲区指针供后续处理
        directBb.flip();

        MyCustomMethodToProcessData(directBb);
    }
} finally {
    ((ByteBuf) msg).release();
}

关键:将ByteBuffer池的存储对象改为Native Direct ByteBuffer,彻底消除堆缓冲区的中转拷贝。

方案二:底层内存地址拷贝(高性能但需谨慎使用)

若receivingBuf是Netty的DirectByteBuf(NioSocketChannel默认接收缓冲区通常为Direct类型),可借助Unsafe API直接操作内存地址完成拷贝,完全规避JVM层面的数据复制:

import sun.misc.Unsafe;
import java.lang.reflect.Field;

// 提前通过反射获取Unsafe实例(JDK9+需配置模块访问权限)
private static final Unsafe UNSAFE;
static {
    try {
        Field field = Unsafe.class.getDeclaredField("theUnsafe");
        field.setAccessible(true);
        UNSAFE = (Unsafe) field.get(null);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

// ChannelRead逻辑实现
try {
    receivingBuf.writeBytes((ByteBuf) msg);

    if (receivingBuf.readableBytes() >= nextPacketLength) {
        ByteBuffer directBb = ByteBufferPoolManager.getDirectByteBuffer();
        int targetLength = nextPacketLength - 12;
        
        // 获取Netty DirectByteBuf的内存起始地址+当前读指针偏移
        long srcAddr = ((DirectByteBuf) receivingBuf).memoryAddress() + receivingBuf.readerIndex();
        // 获取目标Native Direct ByteBuffer的内存起始地址
        long dstAddr = UNSAFE.addressOf(directBb);
        
        // 直接执行内存拷贝
        UNSAFE.copyMemory(null, srcAddr, null, dstAddr, targetLength);
        
        // 更新ByteBuf的读指针位置
        receivingBuf.readerIndex(receivingBuf.readerIndex() + targetLength);
        // 重置目标缓冲区指针
        directBb.position(0);
        directBb.limit(targetLength);

        MyCustomMethodToProcessData(directBb);
    }
} finally {
    ((ByteBuf) msg).release();
}

注意:该方案依赖Unsafe私有API,不同JDK版本存在兼容性风险;若receivingBuf为HeapByteBuf,需先转为DirectByteBuf再操作(可通过receivingBuf.direct()判断类型)。

方案三:Channel专属Direct缓冲区中转(次优但易实现)

若暂时无法修改ByteBuffer池的实现,可为每个Channel分配一个固定大小的Direct ByteBuffer作为专属中转,仅在首次初始化时分配,后续复用:

import io.netty.util.AttributeKey;

// 在ChannelHandler的handlerAdded方法中初始化专属缓冲区
@Override
public void handlerAdded(ChannelHandlerContext ctx) {
    // 根据业务最大包长度分配Direct ByteBuffer
    ByteBuffer channelDirectBuf = ByteBuffer.allocateDirect(maxPacketLength).order(ByteOrder.nativeOrder());
    ctx.channel().attr(AttributeKey.valueOf("CHANNEL_DIRECT_BUF")).set(channelDirectBuf);
}

// ChannelRead逻辑实现
try {
    receivingBuf.writeBytes((ByteBuf) msg);

    if (receivingBuf.readableBytes() >= nextPacketLength) {
        int targetLength = nextPacketLength - 12;
        // 获取Channel专属Direct中转缓冲区
        ByteBuffer channelDirectBuf = ctx.channel().attr(AttributeKey.valueOf("CHANNEL_DIRECT_BUF")).get();
        
        channelDirectBuf.position(0);
        channelDirectBuf.limit(targetLength);
        receivingBuf.readBytes(channelDirectBuf);
        channelDirectBuf.flip();
        
        // 将Direct缓冲区的数据写入目标Native Direct ByteBuffer(Direct到Direct的拷贝性能远高于堆到Direct)
        ByteBuffer targetBb = ByteBufferPoolManager.getDirectByteBuffer();
        targetBb.position(0);
        targetBb.limit(targetLength);
        targetBb.put(channelDirectBuf);
        targetBb.flip();

        MyCustomMethodToProcessData(targetBb);
    }
} finally {
    ((ByteBuf) msg).release();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 10:10:52