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非池化?相关推荐
- java 查看堆外内存占用_如何监控和诊断JVM堆内和堆外内存使用?
上一讲我介绍了 JVM 内存区域的划分,总结了相关的一些概念,今天我将结合 JVM 参数.工具等方面,进一步分析 JVM 内存结构,包括外部资料相对较少的堆外部分. 今天我要问你的问题是,如何监控和诊 ...
- java堆内与堆外数据交互_Java:汇总堆外数据
java堆内与堆外数据交互 探索如何以最小的垃圾回收影响和最大的内存利用率创建堆外聚合. 使用Java Map,List和Object创建大型聚合通常会产生大量堆内存开销. 这也意味着,一旦聚合超 ...
- Spark 内存管理堆内和堆外内存规划_大数据培训
堆内和堆外内存规划 作为一个 JVM 进程,Executor 的内存管理建立在 JVM 的内存管理之上,Spark 对 JVM 的堆内(On-heap)空间进行了更为详细的分配,以充分利用内存.同时, ...
- bytebuf池_netty中的ByteBuf
网络数据的基本单位总是字节.Java NIO 提供了 ByteBuffer 作为它 的字节容器,但是这个类使用起来过于复杂,而且也有些繁琐. Netty 的 ByteBuffer 替代品是 ByteB ...
- bytebuf池_Netty篇:ByteBuf之内存池源码分析
Netty的内存池的实现有些复杂,使用了大量的位运算,晦涩难懂,不过万能的博客上好多大神已经介绍的非常详细,推荐四篇很详细很棒的源码分析的文章链接,本文根据自己的理解顺一下思路,内容主要也是出自以下四 ...
- bytebuf池_Netty java从ByteBuf获取数据
ByteBuf buf = ... byte[] bytes = new byte[buf.readableBytes()]; buf.readBytes(bytes); 如果您不希望readerIn ...
- 使用堆内内存HeapByteBuffer的注意事项
分享一个很多人容易踩的一个坑:HeapByteBuffer 的使用问题.我们都知道 NIO 分装了 ByteBuffer 接口,使得 filechannel 的文件 IO API 变得非常的简单.By ...
- spark从入门到精通spark内存管理详解- 堆内堆外内存管理
前言 Spark作为一个基于内存的分布式计算引擎,其内存管理模块在整个系统中扮演着非常重要的角色.理解Spark内存管理的基本原理,有助于更好地开发Spark应用程序和进行性能调优.本文将详细介绍两部 ...
- Netty 的 ByteBuf 是如何支持 堆内存非池化 实现的
Netty的ByteBuf是如何支持堆内存非池化实现的 ByteBuffer 从实现方式上分成 HeapByteBuffer 和 DirectByteBuffer 两种内存实现方式, HeapByte ...
最新文章
- js更改html元素颜色,HTML - 使用JS根据值更改文本的颜色
- 文件系统与数据库的优缺点
- 结果集(ResultSet)用法
- 三甲医院需要部署哪些网络安全设备
- Node.js环境搭建npm安装
- 【原创】cocos2d-x3.9蓝牙开发之蓝牙开启
- 将COleDateTime类型数据转换成char *数据
- showModalDialog和showModelessDialog使用心得*转*
- svr测试用MATLAB,基于MATLAB的SVR回归模型的设计方案.doc
- java编程入门到精通课后答案,附源代码
- Python 好友管理系统【简单易懂,代码可以直接运行】
- elasticsearch-carrot2插件打包
- 2021 个人成长复盘
- dbm与mysql_关于dBm与功率转换
- STM32 Flash读写;Flash地址对应的存储内容及方式;
- Python之网络编程
- 「PyTorch自然语言处理系列」7. 自然语言处理的进阶序列模型
- Redis Cluster节点添加/删除实录
- Java中的Filter
- JavaScript代码在哪里放置?