bytebuf池_Netty默认的Bytebuf是堆内还是堆外?池化or非池化?
開篇
Netty的ByteBuf有從不同角度有如下2個(gè)分類,4種組合!
堆外內(nèi)存和堆內(nèi)內(nèi)存
池化和非池化
我們?cè)诶肗etty做底層通信框架的時(shí)候,會(huì)默認(rèn)給我們的到底是哪一種組合了?
分析
池化分析
Netty的Boostrap啟動(dòng)類按照標(biāo)準(zhǔn)模板,通常會(huì)添加這個(gè)配置option(ChannelOption.ALLOCATOR, ByteBufAllocator.DEFAULT)
val serverBootstrap = ServerBootstrap().group(bossGroup, workGroup)
.channel(NioServerSocketChannel::class.java) //配置客戶端的channel類型 .option(ChannelOption.ALLOCATOR, ByteBufAllocator.DEFAULT)
//.....
那么通過默認(rèn)的ByteBufAllocator.DEFAULT分配出來的是哪一種組合了?我們來通過代碼分析。
首先看看這個(gè)ByteBufAllocator.DEFAULT創(chuàng)建了一個(gè)什么類
public interface ByteBufAllocator {
ByteBufAllocator DEFAULT = ByteBufUtil.DEFAULT_ALLOCATOR;
}
繼續(xù)調(diào)用下去,下述代碼省略了一些無關(guān)的細(xì)節(jié)!
public final class ByteBufUtil {
static final ByteBufAllocator DEFAULT_ALLOCATOR;
static {
//核心語句 String allocType = SystemPropertyUtil.get(
"io.netty.allocator.type", PlatformDependent.isAndroid() ? "unpooled" : "pooled");
allocType = allocType.toLowerCase(Locale.US).trim();
ByteBufAllocator alloc;
if ("unpooled".equals(allocType)) {
alloc = UnpooledByteBufAllocator.DEFAULT;
} else if ("pooled".equals(allocType)) {
alloc = PooledByteBufAllocator.DEFAULT;
} else {
alloc = PooledByteBufAllocator.DEFAULT;
}
//這里賦值了噢... DEFAULT_ALLOCATOR = alloc;
}
上述代碼最為核心的一句是:
String allocType = SystemPropertyUtil.get(
"io.netty.allocator.type", PlatformDependent.isAndroid() ? "unpooled" : "pooled")
其表達(dá)的意思是
從系統(tǒng)配置(通常是啟動(dòng)的命令行給的)中讀取io.netty.allocator.type,如果能夠讀取到,那么按照配置設(shè)置。但是這個(gè)參數(shù)我們通常是沒有設(shè)置的,所以會(huì)進(jìn)行第二步判定
當(dāng)讀取不到的情況下,又進(jìn)行了一個(gè)判定:PlatformDependent.isAndroid(),當(dāng)Netty運(yùn)行在Android的時(shí)候是unpooled,否則是pooled
后面的代碼就是根據(jù)pooled和unpooled來進(jìn)行對(duì)象初始化了。
綜上,我們大多數(shù)時(shí)候啟動(dòng)參數(shù)都是沒有加對(duì)應(yīng)配置的,且運(yùn)行在非安卓的系統(tǒng),所以是pooled的ByteBuf
堆外/堆外
接下來還需要確定默認(rèn)情況下分配的ByteBuf是分配到堆內(nèi)還是堆外的,從PooledByteBufAllocator.DEFAULT;點(diǎn)進(jìn)去可以看到這個(gè)代碼
public static final PooledByteBufAllocator DEFAULT =
new PooledByteBufAllocator(PlatformDependent.directBufferPreferred());
這個(gè)構(gòu)造函數(shù)的參數(shù)directBufferPreferred的中文意思不就是偏向堆外內(nèi)存嗎?不過按照傳統(tǒng)這個(gè)應(yīng)該是一個(gè)boolean的變量,猜測(cè)了這些,我們繼續(xù)看經(jīng)過省略的源碼PlatformDependent。
public final class PlatformDependent {
private static final boolean DIRECT_BUFFER_PREFERRED;
static {
if (!isAndroid()) {
if (javaVersion() >= 9) {
CLEANER = CleanerJava9.isSupported() ? new CleanerJava9() : NOOP;
} else {
CLEANER = CleanerJava6.isSupported() ? new CleanerJava6() : NOOP;
}
} else {
CLEANER = NOOP;
}
DIRECT_BUFFER_PREFERRED = CLEANER != NOOP && !SystemPropertyUtil.getBoolean("io.netty.noPreferDirect", false);
}
核心的參數(shù)DIRECT_BUFFER_PREFERRED要想為true必須經(jīng)過2步:
通過判定獲取CLEANER,這個(gè)判定牽扯到了另外的判定,這里就不貼代碼了,意思應(yīng)該就是有沒有堆外內(nèi)存的清理辦法,Java7+應(yīng)該都有的
然后判定系統(tǒng)參數(shù)io.netty.noPreferDirect是不是為false
通常Java后端的系統(tǒng)這2個(gè)條件都是滿足的,所以恭喜:DIRECT_BUFFER_PREFERRED為true,堆外內(nèi)存。
優(yōu)劣
通過上面分析,我們知道了Netty默認(rèn)的ByteBuf是堆外的池化模式,那么池化與否和堆外與否各自的優(yōu)劣在哪里!?
通常池化意味者可以復(fù)用資源,減少系統(tǒng)資源的開銷
堆外內(nèi)存可以使用更多可用的空間,畢竟Java虛擬機(jī)的大小一般都要小于系統(tǒng)的大小。但是江湖傳言堆外內(nèi)存的開辟比堆內(nèi)內(nèi)存的開辟慢,這一點(diǎn)我不太能理解,這里記錄下。
以下是我在發(fā)文后的第二天從java.nio.ByteBuffer看到的文檔注釋!
A direct byte buffer may be created by invoking the {@link #allocateDirect(int) allocateDirect} factory method of this class. The buffers returned by this method typically have somewhat higher allocation and deallocation costs than non-direct buffers.
上文的意思翻譯下就是
堆外內(nèi)存的創(chuàng)建可以通過調(diào)用allocateDirect這個(gè)工廠方法來創(chuàng)建。通過這個(gè)方法創(chuàng)建的buffer通常來說會(huì)比非堆外內(nèi)存有更高的創(chuàng)建和釋放成本。
這里我還是納悶啊!**不是說C的效率要高于Java嗎?為什么堆外內(nèi)存的創(chuàng)建和釋放會(huì)比堆內(nèi)內(nèi)存的成本更高了?**有知道的大佬嗎?
結(jié)語
本篇文章主要通過啟動(dòng)參數(shù)的配置,進(jìn)行了源碼分析,確認(rèn)了Netty的ByteBuf使用的是堆外的池外模式。
騏驥一躍,不能十步。駑馬十駕,功在不舍。
總結(jié)
以上是生活随笔為你收集整理的bytebuf池_Netty默认的Bytebuf是堆内还是堆外?池化or非池化?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HashMap 学习笔记
- 下一篇: cad连接不同线段的端点_CAD绘图中两