ByteBuf的扩容机制

Netty ByteBuf 的扩容机制主要由 AbstractByteBuf 类及其子类中的 ensureWritable 方法及其相关逻辑控制,并受到 ByteBufAllocator 和 RecvByteBufAllocator(特别是 AdaptiveRecvByteBufAllocator)的影响。

1. 扩容触发条件

当调用 ByteBuf 的写入方法(如 writeByteswriteInt 等),如果写入的数据量超过了当前 ByteBuf 的可写容量(writableBytes()),就会触发扩容操作。以下是一个简单示例:

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;

public class ByteBufExpandExample {
    public static void main(String[] args) {
        ByteBuf buffer = Unpooled.buffer(10); // 初始容量为 10
        System.out.println("初始容量: " + buffer.capacity());
        byte[] data = new byte[20];
        try {
            buffer.writeBytes(data); // 尝试写入 20 字节数据,会触发扩容
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("扩容后容量: " + buffer.capacity());
        buffer.release();
    }
}

2. 核心扩容方法

ByteBuf 的扩容主要通过 capacity(int newCapacity) 方法实现,不同的 ByteBuf 实现类会重写该方法来实现具体的扩容逻辑。以下是一些常见 ByteBuf 实现类的 capacity 方法:

2.1 UnpooledHeapByteBuf
@Override
public ByteBuf capacity(int newCapacity) {
    checkNewCapacity(newCapacity);
    byte[] oldArray = array;
    int oldCapacity = oldArray.length;
    if (newCapacity == oldCapacity) {
        return this;
    }

    int bytesToCopy;
    if (newCapacity > oldCapacity) {
        bytesToCopy = oldCapacity;
    } else {
        trimIndicesToCapacity(newCapacity);
        bytesToCopy = newCapacity;
    }
    byte[] newArray = allocateArray(newCapacity);
    System.arraycopy(oldArray, 0, newArray, 0, bytesToCopy);
    setArray(newArray);
    freeArray(oldArray);
    return this;
}
  • 逻辑说明:首先检查新容量是否合法,然后比较新容量和旧容量。如果新容量大于旧容量,将旧数组中的数据复制到新数组;如果新容量小于旧容量,先调整读写索引,再复制数据。最后释放旧数组,设置新数组。
2.2 PooledByteBuf
@Override
public final ByteBuf capacity(int newCapacity) {
    if (newCapacity == length) {
        ensureAccessible();
        return this;
    }
    checkNewCapacity(newCapacity);
    if (!chunk.unpooled) {
        if (newCapacity > length) {
            if (newCapacity <= maxLength) {
                length = newCapacity;
                return this;
            }
        } else if (newCapacity > maxLength >>> 1 &&
                (maxLength > 512 || newCapacity > maxLength - 16)) {
            length = newCapacity;
            trimIndicesToCapacity(newCapacity);
            return this;
        }
    }

    PooledByteBufAllocator.onReallocateBuffer(this, newCapacity);
    chunk.arena.reallocate(this, newCapacity);
    return this;
}
  • 逻辑说明:先检查新容量是否等于当前长度,如果是则直接返回。然后检查新容量是否在合适的范围内,如果是则更新长度并返回。否则,调用 PooledByteBufAllocatorChunkArena 的相关方法进行重新分配。

3. 计算新容量的策略

在进行扩容时,需要计算新的容量。ByteBufAllocator 提供了 calculateNewCapacity 方法来计算新容量,不同的 ByteBufAllocator 实现类会重写该方法以实现不同的计算逻辑。例如,AbstractByteBufAllocator 的实现如下:

@Override
public int calculateNewCapacity(int minNewCapacity, int maxCapacity) {
    checkPositiveOrZero(minNewCapacity, "minNewCapacity");
    if (minNewCapacity > maxCapacity) {
        throw new IllegalArgumentException(String.format(
                "minNewCapacity: %d (expected: not greater than maxCapacity(%d)",
                minNewCapacity, maxCapacity));
    }
    final int threshold = CALCULATE_THRESHOLD; // 4 MiB page

    if (minNewCapacity == threshold) {
        return threshold;
    }

    // 如果超过阈值,不进行双倍扩容,而是按阈值增加
    if (minNewCapacity > threshold) {
        int newCapacity = minNewCapacity / threshold * threshold;
        if (newCapacity > maxCapacity - threshold) {
            newCapacity = maxCapacity;
        } else {
            newCapacity += threshold;
        }
        return newCapacity;
    }

    // 64 <= newCapacity 是 2 的幂次方 <= 阈值
    final int newCapacity = MathUtil.findNextPositivePowerOfTwo(Math.max(minNewCapacity, 64));
    return Math.min(newCapacity, maxCapacity);
}
  • 逻辑说明

    • 首先检查最小新容量是否合法,是否超过最大容量。
    • 如果最小新容量等于阈值(4 MiB),则直接返回阈值。
    • 如果最小新容量超过阈值,不进行双倍扩容,而是按阈值增加。
    • 如果最小新容量小于阈值,将其调整为不小于 64 且是 2 的幂次方的数。
    • 最后返回不超过最大容量的新容量。

4. 总结

Netty 的 ByteBuf 扩容机制通过不同的实现类和方法,提供了灵活且高效的内存管理方案。在实际使用中,可以根据具体的需求选择合适的 ByteBuf 实现类和扩容策略,以提高系统的性能和稳定性。同时,了解扩容机制有助于更好地使用 ByteBuf,避免不必要的内存开销和性能问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值