bytebuf池_Netty默认的Bytebuf是堆内还是堆外?池化or非池化?
開篇
Netty的ByteBuf有從不同角度有如下2個分類,4種組合!
堆外內存和堆內內存
池化和非池化
我們在利用Netty做底層通信框架的時候,會默認給我們的到底是哪一種組合了?
分析
池化分析
Netty的Boostrap啟動類按照標準模板,通常會添加這個配置option(ChannelOption.ALLOCATOR, ByteBufAllocator.DEFAULT)
val serverBootstrap = ServerBootstrap().group(bossGroup, workGroup)
.channel(NioServerSocketChannel::class.java) //配置客戶端的channel類型 .option(ChannelOption.ALLOCATOR, ByteBufAllocator.DEFAULT)
//.....
那么通過默認的ByteBufAllocator.DEFAULT分配出來的是哪一種組合了?我們來通過代碼分析。
首先看看這個ByteBufAllocator.DEFAULT創建了一個什么類
public interface ByteBufAllocator {
ByteBufAllocator DEFAULT = ByteBufUtil.DEFAULT_ALLOCATOR;
}
繼續調用下去,下述代碼省略了一些無關的細節!
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")
其表達的意思是
從系統配置(通常是啟動的命令行給的)中讀取io.netty.allocator.type,如果能夠讀取到,那么按照配置設置。但是這個參數我們通常是沒有設置的,所以會進行第二步判定
當讀取不到的情況下,又進行了一個判定:PlatformDependent.isAndroid(),當Netty運行在Android的時候是unpooled,否則是pooled
后面的代碼就是根據pooled和unpooled來進行對象初始化了。
綜上,我們大多數時候啟動參數都是沒有加對應配置的,且運行在非安卓的系統,所以是pooled的ByteBuf
堆外/堆外
接下來還需要確定默認情況下分配的ByteBuf是分配到堆內還是堆外的,從PooledByteBufAllocator.DEFAULT;點進去可以看到這個代碼
public static final PooledByteBufAllocator DEFAULT =
new PooledByteBufAllocator(PlatformDependent.directBufferPreferred());
這個構造函數的參數directBufferPreferred的中文意思不就是偏向堆外內存嗎?不過按照傳統這個應該是一個boolean的變量,猜測了這些,我們繼續看經過省略的源碼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);
}
核心的參數DIRECT_BUFFER_PREFERRED要想為true必須經過2步:
通過判定獲取CLEANER,這個判定牽扯到了另外的判定,這里就不貼代碼了,意思應該就是有沒有堆外內存的清理辦法,Java7+應該都有的
然后判定系統參數io.netty.noPreferDirect是不是為false
通常Java后端的系統這2個條件都是滿足的,所以恭喜:DIRECT_BUFFER_PREFERRED為true,堆外內存。
優劣
通過上面分析,我們知道了Netty默認的ByteBuf是堆外的池化模式,那么池化與否和堆外與否各自的優劣在哪里!?
通常池化意味者可以復用資源,減少系統資源的開銷
堆外內存可以使用更多可用的空間,畢竟Java虛擬機的大小一般都要小于系統的大小。但是江湖傳言堆外內存的開辟比堆內內存的開辟慢,這一點我不太能理解,這里記錄下。
以下是我在發文后的第二天從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.
上文的意思翻譯下就是
堆外內存的創建可以通過調用allocateDirect這個工廠方法來創建。通過這個方法創建的buffer通常來說會比非堆外內存有更高的創建和釋放成本。
這里我還是納悶啊!**不是說C的效率要高于Java嗎?為什么堆外內存的創建和釋放會比堆內內存的成本更高了?**有知道的大佬嗎?
結語
本篇文章主要通過啟動參數的配置,進行了源碼分析,確認了Netty的ByteBuf使用的是堆外的池外模式。
騏驥一躍,不能十步。駑馬十駕,功在不舍。
總結
以上是生活随笔為你收集整理的bytebuf池_Netty默认的Bytebuf是堆内还是堆外?池化or非池化?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HashMap 学习笔记
- 下一篇: cad连接不同线段的端点_CAD绘图中两