??我們知道在實例化一個ByteBuf對象的時候,是可以設(shè)置一個capacity和一個maxCapacity窜骄,當(dāng)writerIndex達(dá)到capacity的時候,再往里面寫入內(nèi)容女淑,ByteBuf就會進行擴容。
??下面我們來看一些ByteBuf是怎樣進行擴容的:
??我們先看一下調(diào)用ByteBuf的writeByte(int value)寫入一個字節(jié)的數(shù)據(jù)会宪。因為ByteBuf的writeByte(int value)是一個抽象方法箱残,它的具體實現(xiàn)是在AbstractByteBuf里面
public ByteBuf writeByte(int value) {
ensureWritable0(1);
_setByte(writerIndex++, value);
return this;
}
??我們能看到會先調(diào)用ensureWritable0()方法來檢查是否能往里面寫入數(shù)據(jù)求妹,傳入1
final void ensureWritable0(int minWritableBytes) {
ensureAccessible();
if (minWritableBytes <= writableBytes()) {
return;
}
if (checkBounds) {
if (minWritableBytes > maxCapacity - writerIndex) {
throw new IndexOutOfBoundsException(String.format(
"writerIndex(%d) + minWritableBytes(%d) exceeds maxCapacity(%d): %s",
writerIndex, minWritableBytes, maxCapacity, this));
}
}
// Normalize the current capacity to the power of 2.
int newCapacity = alloc().calculateNewCapacity(writerIndex + minWritableBytes, maxCapacity);
// Adjust to the new capacity.
capacity(newCapacity);
}
??ensureAccessible()方法是檢查refCnt是否為0研乒,為0代表該ByteBuf對象以被釋放汹忠,會拋IllegalReferenceCountException。
??接下來判斷minWritableBytes是否小于或等于writableBytes,如果滿足代表還有空間滿足寫入數(shù)據(jù)宽菜,則直接返回奖地。如果不滿足,則判斷是否檢查邊界赋焕,checkBounds是個boolean值,可在啟動JVM的時候由io.netty.buffer.checkBounds參數(shù)指定仰楚,其默認(rèn)值是true隆判。如果checkBounds為true,判斷將要寫入的字節(jié)數(shù)是否大于最大可寫入的字節(jié)數(shù)(maxCapacity - writerIndex)僧界,如果大于直接拋異常侨嘀,否則繼續(xù)執(zhí)行。
??接下來會調(diào)用ByteBufAllocator的calculateNewCapacity計算新的capacity捂襟。方法的實現(xiàn)在AbstractByteBufAllocator里面:
public int calculateNewCapacity(int minNewCapacity, int maxCapacity) {
if (minNewCapacity < 0) {
throw new IllegalArgumentException("minNewCapacity: " + minNewCapacity + " (expected: 0+)");
}
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 over threshold, do not double but just increase by threshold.
if (minNewCapacity > threshold) {
int newCapacity = minNewCapacity / threshold * threshold;
if (newCapacity > maxCapacity - threshold) {
newCapacity = maxCapacity;
} else {
newCapacity += threshold;
}
return newCapacity;
}
// Not over threshold. Double up to 4 MiB, starting from 64.
int newCapacity = 64;
while (newCapacity < minNewCapacity) {
newCapacity <<= 1;
}
return Math.min(newCapacity, maxCapacity);
}
??我們能看到擴容是有一個閥值(CALCULATE_THRESHOLD)的咬腕,為4MB大小,當(dāng)所需容量大性岷伞(minNewCapacity)小于閥值(threshold)的時候涨共,新的容量(newCapacity)都是是以64位基數(shù)向坐移位位計算出來的,通過循環(huán)宠漩,每次移動移1位举反,直到newCapacity>=minNewCapacity為止,如果計算出來newCapacity大于maxCapacity扒吁,則返回maxCapacity火鼻,否則返回newCapacity。也就是說當(dāng)minNewCapacity=300的時候雕崩,newCapacity=512魁索。
??當(dāng)minNewCapacity>=threshold的時候,則先計算minNewCapacity / threshold * threshold的大小盼铁,如果這個值在加上一個threshold(4MB)大于newCapacity的時候粗蔚,則newCapacity的值取maxCapacity,否則newCapacity=minNewCapacity / threshold * threshold+threshold捉貌。
??再回到ensureWritable0()方法支鸡,我們能看到,拿到計算出來的newCapacity趁窃,原后調(diào)用capacity(newCapacity)方法將新的capacity設(shè)置進去牧挣。