bytebuf池_Netty默认的Bytebuf是堆内还是堆外?池化or非池化?
Posted 天涯泪小武
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 undefined
ByteBufAllocator DEFAULT = ByteBufUtil.DEFAULT_ALLOCATOR;
继续调用下去,下述代码省略了一些无关的细节!
public final class ByteBufUtil undefined
static final ByteBufAllocator DEFAULT_ALLOCATOR;
static undefined
//核心语句 String allocType = SystemPropertyUtil.get(
"io.netty.allocator.type", PlatformDependent.isandroid() ? "unpooled" : "pooled");
allocType = allocType.toLowerCase(Locale.US).trim();
ByteBufAllocator alloc;
if ("unpooled".equals(allocType)) undefined
alloc = UnpooledByteBufAllocator.DEFAULT;
else if ("pooled".equals(allocType)) undefined
alloc = PooledByteBufAllocator.DEFAULT;
else undefined
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 undefined
private static final boolean DIRECT_BUFFER_PREFERRED;
static undefined
if (!isAndroid()) undefined
if (javaVersion() >= 9) undefined
CLEANER = CleanerJava9.isSupported() ? new CleanerJava9() : NOOP;
else undefined
CLEANER = CleanerJava6.isSupported() ? new CleanerJava6() : NOOP;
else undefined
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非池化?的主要内容,如果未能解决你的问题,请参考以下文章
bytebuf池_Netty默认的Bytebuf是堆内还是堆外?池化or非池化?
bytebuf池_Netty默认的Bytebuf是堆内还是堆外?池化or非池化?
Netty_03_ByteBuf和网络中拆包粘包问题及其解决