Netty中的内存分配是基于ByteBufAllocator这个接口实现的,通过对它的具体实现,可以用来分配我们之前描述过的任意类型的BytebBuf实例;我们先看一下ByteBufAllocator接口中的定义的关键方法

一、ByteBufAllocator 构造

public interface ByteBufAllocator {

    ByteBufAllocator DEFAULT = ByteBufUtil.DEFAULT_ALLOCATOR;

    //根据具体实现返回基于直接内存或堆内内存的ByteBuf
ByteBuf buffer(); //根据具体实现返回一个给定初始容量的基于直接内存或堆内内存的ByteBuf
ByteBuf buffer(int initialCapacity); //根据具体实现返回一个给定初始容量与最大量的基于直接内存或堆内内存的ByteBuf
ByteBuf buffer(int initialCapacity, int maxCapacity); //返回一个用于套接字操作的ByteBuf
ByteBuf ioBuffer(); //返回一个用于套接字操作的给定初始量ByteBuf
ByteBuf ioBuffer(int initialCapacity); //返回一个用于套接字操作的给定初始量与最大量的ByteBuf
ByteBuf ioBuffer(int initialCapacity, int maxCapacity); //返回一个基于堆内内存的ByteBuf
ByteBuf heapBuffer(); //返回一个给定初始量基于堆内内存的ByteBuf
ByteBuf heapBuffer(int initialCapacity); //返回一个给定初始量与最大量的基于堆内内存的ByteBuf
ByteBuf heapBuffer(int initialCapacity, int maxCapacity); //返回一个基于直接内存的ByteBuf
ByteBuf directBuffer(); //返回一个给定初始量基于直接内存的ByteBuf
ByteBuf directBuffer(int initialCapacity); //返回一个给定初始量与最大量的基于直接内存的ByteBuf
ByteBuf directBuffer(int initialCapacity, int maxCapacity); //返回一个基于复合缓冲区的ByteBuf,基于堆还是直接内存看具体实现
CompositeByteBuf compositeBuffer(); //返回一个给定最大量的基于复合缓冲区的ByteBuf,基于堆还是直接内存看具体实现
CompositeByteBuf compositeBuffer(int maxNumComponents); //返回一个基于堆内存的CompositeByteBuf
CompositeByteBuf compositeHeapBuffer(); //返回一个给定最大量基于堆内存的CompositeByteBuf
CompositeByteBuf compositeHeapBuffer(int maxNumComponents); //返回一个基于直接内存的CompositeByteBuf
CompositeByteBuf compositeDirectBuffer(); //返回一个给定最大量的基于直接内存的CompositeByteBuf
CompositeByteBuf compositeDirectBuffer(int maxNumComponents); //直接内存是否池化管理
boolean isDirectBufferPooled(); //计算bytebuf需要扩展时的新容量
int calculateNewCapacity(int minNewCapacity, int maxCapacity);
}

可以看到接口中定义的方法基本都是用于分配不同类型的内存,接下来我们看下基于ByteBufAllocator 接口的具体实现类。

看下实现ByteBufAllocator 接口的类结构图

顶层抽象类AbstractByteBufAllocator下有两大子类PooledByteBufAllocator与UnpooledByteBufAllocator,分别用于池化与非池化内存的构造;

二、ByteBufAllocator 使用

首先我们需要注意下ChannelOption.ALLOCATOR这个配置项,如果不进行特殊配置, 默认为PooledByteBufAllocator,默认ByteBuf类型为PooledUnsafeDirectByteBuf,这里演示需要改为UnpooledByteBufAllocator

b.childOption(ChannelOption.ALLOCATOR, UnpooledByteBufAllocator.DEFAULT);

在数据入站Handler中,我们通过使用不同的BufAllocator实现类来分配ByteBuf进行对比,主要关注下分配的ByteBuf的类型与是否池化

public class BuffHandler extends ChannelInboundHandlerAdapter{

    PooledByteBufAllocator pdallocator = new PooledByteBufAllocator(true);//池化直接内存

    PooledByteBufAllocator pallocator = new PooledByteBufAllocator(false);//池化堆内存

    UnpooledByteBufAllocator adllocator = new UnpooledByteBufAllocator(true);//非池化直接内存

    UnpooledByteBufAllocator allocator = new UnpooledByteBufAllocator(false);//非池化堆内存

    @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ByteBuf outBuffer = (ByteBuf) msg;
System.err.println("outBuffer is :"+outBuffer.getClass());
System.err.println("outBuffer's model is :"+outBuffer.isDirect());
outBuffer = ByteBufAllocator.DEFAULT.buffer();//ByteBufAllocator默认内存类型
System.err.println("ByteBufAllocator.DEFAULT.buffer() is :"+outBuffer.getClass());
System.err.println("ByteBufAllocator.DEFAULT.buffer()'s model is :"+outBuffer.isDirect());
outBuffer = pdallocator.buffer();////池化直接内存
System.err.println("PooledByteBufAllocator(true) is :"+outBuffer.getClass());
System.err.println("PooledByteBufAllocator(true)'s model is :"+outBuffer.isDirect());
outBuffer = pallocator.buffer();//池化队堆内存
System.err.println("PooledByteBufAllocator(false) is :"+outBuffer.getClass());
System.err.println("PooledByteBufAllocator(false)'s model is :"+outBuffer.isDirect());
outBuffer = adllocator.buffer();////非池化直接内存
System.err.println("UnpooledByteBufAllocator(true) is :"+outBuffer.getClass());
System.err.println("UnpooledByteBufAllocator(true)'s model is :"+outBuffer.isDirect());
outBuffer = allocator.buffer();//非池化堆内存
System.err.println("UnpooledByteBufAllocator(false) is :"+outBuffer.getClass());
System.err.println("UnpooledByteBufAllocator(false)'s model is :"+outBuffer.isDirect());
byte[] sendBytes = new byte[] {0x7E,0x01,0x02,0x7e};
outBuffer.writeBytes(sendBytes);
ctx.writeAndFlush(outBuffer);
} @Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
// Close the connection when an exception is raised.
cause.printStackTrace();
ctx.close();
}
}

根据BufAllocator具体实现类与preferDirect参数会分配不同类型的ByteBuf,输出结果如下:

outBuffer is :class io.netty.buffer.UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeNoCleanerDirectByteBuf
outBuffer's model is :true
ByteBufAllocator.DEFAULT.buffer() is :class io.netty.buffer.PooledUnsafeDirectByteBuf
ByteBufAllocator.DEFAULT.buffer()'s model is :true
PooledByteBufAllocator(true) is :class io.netty.buffer.PooledUnsafeDirectByteBuf
PooledByteBufAllocator(true)'s model is :true
PooledByteBufAllocator(false) is :class io.netty.buffer.PooledUnsafeHeapByteBuf
PooledByteBufAllocator(false)'s model is :false
UnpooledByteBufAllocator(true) is :class io.netty.buffer.UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeNoCleanerDirectByteBuf
UnpooledByteBufAllocator(true)'s model is :true
UnpooledByteBufAllocator(false) is :class io.netty.buffer.UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf
UnpooledByteBufAllocator(false)'s model is :false

上面示例中,BufAllocator具体实现基本可以分为以下四种,下面我们对四种分配模式的具体实现进行下追踪与分析

new PooledByteBufAllocator(true);//池化直接内存
new PooledByteBufAllocator(false);//池化堆内存
new UnpooledByteBufAllocator(true);//非池化直接内存
new UnpooledByteBufAllocator(false);//非池化堆内存

三、ByteBufAllocator 实现

ByteBufAllocator.DEFAULT.buffer()

这里使用了 ByteBufUtil   DEFAULT_ALLOCATOR,我们进入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();//读取io.netty.allocator.type配置 //根据配置类型实例化不同类型的BufAllocator实现类
ByteBufAllocator alloc;
if ("unpooled".equals(allocType)) {
// DEFAULT = new UnpooledByteBufAllocator(PlatformDependent.directBufferPreferred());
alloc = UnpooledByteBufAllocator.DEFAULT;
logger.debug("-Dio.netty.allocator.type: {}", allocType);
} else if ("pooled".equals(allocType)) {
// DEFAULT = new PooledByteBufAllocator(PlatformDependent.directBufferPreferred());
alloc = PooledByteBufAllocator.DEFAULT;
logger.debug("-Dio.netty.allocator.type: {}", allocType);
} else {
alloc = PooledByteBufAllocator.DEFAULT;
logger.debug("-Dio.netty.allocator.type: pooled (unknown: {})", allocType);
} DEFAULT_ALLOCATOR = alloc; THREAD_LOCAL_BUFFER_SIZE = SystemPropertyUtil.getInt("io.netty.threadLocalDirectBufferSize", 0);
logger.debug("-Dio.netty.threadLocalDirectBufferSize: {}", THREAD_LOCAL_BUFFER_SIZE); MAX_CHAR_BUFFER_SIZE = SystemPropertyUtil.getInt("io.netty.maxThreadLocalCharBufferSize", 16 * 1024);
logger.debug("-Dio.netty.maxThreadLocalCharBufferSize: {}", MAX_CHAR_BUFFER_SIZE);
}

ByteBufUtil 的静态构造中会根据io.netty.allocator.type配置的不同实例化不同类型的BufAllocator实现类,下面我们看下BufAllocator的两个具体实现类PooledByteBufAllocator与UnpooledByteBufAllocator

PooledByteBufAllocator

在PooledByteBufAllocator构造函数中,首先会进行内存池的详细配置

    public PooledByteBufAllocator(boolean preferDirect, int nHeapArena, int nDirectArena, int pageSize, int maxOrder,
int tinyCacheSize, int smallCacheSize, int normalCacheSize,
boolean useCacheForAllThreads, int directMemoryCacheAlignment) {
super(preferDirect);
//声明一个PoolThreadLocalCache用于内存申请
threadCache = new PoolThreadLocalCache(useCacheForAllThreads);
this.tinyCacheSize = tinyCacheSize;
this.smallCacheSize = smallCacheSize;
this.normalCacheSize = normalCacheSize;
chunkSize = validateAndCalculateChunkSize(pageSize, maxOrder); checkPositiveOrZero(nHeapArena, "nHeapArena");
checkPositiveOrZero(nDirectArena, "nDirectArena"); checkPositiveOrZero(directMemoryCacheAlignment, "directMemoryCacheAlignment");
if (directMemoryCacheAlignment > 0 && !isDirectMemoryCacheAlignmentSupported()) {
throw new IllegalArgumentException("directMemoryCacheAlignment is not supported");
} if ((directMemoryCacheAlignment & -directMemoryCacheAlignment) != directMemoryCacheAlignment) {
throw new IllegalArgumentException("directMemoryCacheAlignment: "
+ directMemoryCacheAlignment + " (expected: power of two)");
} int pageShifts = validateAndCalculatePageShifts(pageSize); if (nHeapArena > 0) {
heapArenas = newArenaArray(nHeapArena);
List<PoolArenaMetric> metrics = new ArrayList<PoolArenaMetric>(heapArenas.length);
for (int i = 0; i < heapArenas.length; i ++) {
PoolArena.HeapArena arena = new PoolArena.HeapArena(this,
pageSize, maxOrder, pageShifts, chunkSize,
directMemoryCacheAlignment);
heapArenas[i] = arena;
metrics.add(arena);
}
heapArenaMetrics = Collections.unmodifiableList(metrics);
} else {
heapArenas = null;
heapArenaMetrics = Collections.emptyList();
} if (nDirectArena > 0) {
directArenas = newArenaArray(nDirectArena);
List<PoolArenaMetric> metrics = new ArrayList<PoolArenaMetric>(directArenas.length);
for (int i = 0; i < directArenas.length; i ++) {
PoolArena.DirectArena arena = new PoolArena.DirectArena(
this, pageSize, maxOrder, pageShifts, chunkSize, directMemoryCacheAlignment);
directArenas[i] = arena;
metrics.add(arena);
}
directArenaMetrics = Collections.unmodifiableList(metrics);
} else {
directArenas = null;
directArenaMetrics = Collections.emptyList();
}
metric = new PooledByteBufAllocatorMetric(this);
}

紧接着看下PooledByteBufAllocator具体的内存分配方法

newDirectBuffer 分配直接内存 
    @Override
protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
PoolThreadCache cache = threadCache.get();
PoolArena<ByteBuffer> directArena = cache.directArena;//具体的内存分配类PoolArena final ByteBuf buf;
if (directArena != null) {//PoolArena就是Netty的内存池实现类。实现具体内存分配
buf = directArena.allocate(cache, initialCapacity, maxCapacity);
} else {
buf = PlatformDependent.hasUnsafe() ?
UnsafeByteBufUtil.newUnsafeDirectByteBuf(this, initialCapacity, maxCapacity) :
new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);
} return toLeakAwareBuffer(buf);
}
heapBuffer 分配堆内内存 
    protected ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity) {
PoolThreadCache cache = threadCache.get();
PoolArena<byte[]> heapArena = cache.heapArena; final ByteBuf buf;
if (heapArena != null) { //通过PoolArena分配堆内内存
buf = heapArena.allocate(cache, initialCapacity, maxCapacity);
} else {
buf = PlatformDependent.hasUnsafe() ?
new UnpooledUnsafeHeapByteBuf(this, initialCapacity, maxCapacity) :
new UnpooledHeapByteBuf(this, initialCapacity, maxCapacity);
} return toLeakAwareBuffer(buf);
}

UnpooledByteBufAllocator

由于采用非池化管理,UnpooledByteBufAllocator构造函数中需要指定内存清理策略

    public UnpooledByteBufAllocator(boolean preferDirect, boolean disableLeakDetector, boolean tryNoCleaner) {
super(preferDirect);
this.disableLeakDetector = disableLeakDetector;
//内存清理策略,默认noCleaner需要使用 unSafe 的 freeMemory 方法释放内存
//noCleaner 使用 unSafe.freeMemory(address);
//hasCleaner 使用 DirectByteBuffer 的 Cleaner 的 clean 方法。
noCleaner = tryNoCleaner && PlatformDependent.hasUnsafe()
&& PlatformDependent.hasDirectBufferNoCleanerConstructor();
}

紧接着看下UnpooledByteBufAllocator具体的内存分配方法

newDirectBuffer 分配直接内存 
    @Override
protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
final ByteBuf buf;
if (PlatformDependent.hasUnsafe()) {//判断是否适用Unsafe操作
buf = noCleaner ? new InstrumentedUnpooledUnsafeNoCleanerDirectByteBuf(this, initialCapacity, maxCapacity) :
new InstrumentedUnpooledUnsafeDirectByteBuf(this, initialCapacity, maxCapacity);
} else {
buf = new InstrumentedUnpooledDirectByteBuf(this, initialCapacity, maxCapacity);
}
return disableLeakDetector ? buf : toLeakAwareBuffer(buf);//是否进行堆外内存泄露监控
}

newHeapBuffer 分配堆内内存 
    @Override
protected ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity) {
return PlatformDependent.hasUnsafe() ?
new InstrumentedUnpooledUnsafeHeapByteBuf(this, initialCapacity, maxCapacity) :
new InstrumentedUnpooledHeapByteBuf(this, initialCapacity, maxCapacity);
}

四、总结

通过以上内容我们梳理了Netty中BufAllocator的具体实现及分配内存的类型,从内存管理模式上分为池化与非池化,从内存分配类型上分为直接内存与堆内内存,本文我们只是初步对其进行了总结,Netty分配内存的具体实现及精巧设计都还未涉及,后续我们会继续对其进行进一步的探究,希望本文对大家能有所帮助,其中如有不足与不正确的地方还望指出与海涵。

   关注微信公众号,查看更多技术文章。

Netty源码分析之ByteBuf(二)—内存分配器ByteBufAllocator的更多相关文章

  1. Netty 源码分析系列(二)Netty 架构设计

    前言 上一篇文章,我们对 Netty做了一个基本的概述,知道什么是Netty以及Netty的简单应用. Netty 源码分析系列(一)Netty 概述 本篇文章我们就来说说Netty的架构设计,解密高 ...

  2. Netty源码分析 (十二)----- 心跳服务之 IdleStateHandler 源码分析

    什么是心跳机制? 心跳说的是在客户端和服务端在互相建立ESTABLISH状态的时候,如何通过发送一个最简单的包来保持连接的存活,还有监控另一边服务的可用性等. 心跳包的作用 保活Q:为什么说心跳机制能 ...

  3. Netty源码分析之ByteBuf引用计数

    引用计数是一种常用的内存管理机制,是指将资源的被引用次数保存起来,当被引用次数变为零时就将其释放的过程.Netty在4.x版本开始使用引用计数机制进行部分对象的管理,其实现思路并不是特别复杂,它主要涉 ...

  4. Netty源码分析之NioEventLoop(二)—NioEventLoop的启动

    上篇文章中我们对Netty中NioEventLoop创建流程与源码进行了跟踪分析.本篇文章中我们接着分析NioEventLoop的启动流程: Netty中会在服务端启动和新连接接入时通过chooser ...

  5. Netty源码分析之ChannelPipeline(二)—ChannelHandler的添加与删除

    上篇文章中,我们对Netty中ChannelPipeline的构造与初始化进行了分析与总结,本篇文章我们将对ChannelHandler的添加与删除操作进行具体的的代码分析: 一.ChannelHan ...

  6. [编织消息框架][netty源码分析]11 ByteBuf 实现类UnpooledHeapByteBuf职责与实现

    每种ByteBuf都有相应的分配器ByteBufAllocator,类似工厂模式.我们先学习UnpooledHeapByteBuf与其对应的分配器UnpooledByteBufAllocator 如何 ...

  7. [编织消息框架][netty源码分析]10 ByteBuf 与 ByteBuffer

    因为jdk ByteBuffer使用起来很麻烦,所以netty研发出ByteBuf对象维护管理内存使用ByteBuf有几个概念需要知道1.向ByteBuf提取数据时readerIndex记录最后读取坐 ...

  8. Netty源码分析之ByteBuf(一)—ByteBuf中API及类型概述

    ByteBuf是Netty中主要的数据容器与操作工具,也是Netty内存管理优化的具体实现,本章我们先从整体上对ByteBuf进行一个概述: AbstractByteBuf是整个ByteBuf的框架类 ...

  9. [编织消息框架][netty源码分析]13 ByteBuf 实现类CompositeByteBuf职责与实现

    public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements Iterable<ByteBuf ...

随机推荐

  1. CGANs

    Introducation 1. intruduce the conditional version of GANs, which can be constructed by simply feedi ...

  2. java前后端开发需掌握的框架及技术

    一.Java开发 1.J2EE架构及主流框架,spring4.spring boot.spring MVC.spring Security.spring cloud.struct2.hibernate ...

  3. JavaScript实现基于对象的栈

    class Stack { constructor() { this.count = 0; this.items = {}; } push(element) { this.items[this.cou ...

  4. 活动可视化搭建系统——你的KPI被我承包了

    前言 对于C端业务偏多的公司来说,在增长.运营等各方同学的摧残下永远绕不过去的一个坑就是大量的H5页面开发,它可能是一个下载.需求告知.产品介绍.营销活动等页面.此类需求都有几个明显的缺点: •开发性 ...

  5. CodeForces 1025G Company Acquisitions

    题意 描述有点麻烦,就不写了. \(\texttt{Data Range:}1\leq n\leq 500\) 题解 势能函数这个东西好神啊-- 这个题目用常规的 DP 好像做不出来,所以我们可以考虑 ...

  6. modbus协议开关量采集模块

    modbus协议开关量采集模块是指的使用Modbus协议的进行信号的采集与控制的一种设备. Modbus 协议设备都具有唯一的 Modbus 地址,众山 DTU 默认 Modbus 地址为 100,用 ...

  7. eyou去版权

    公司老板要求做一个自己门户网站,苦于公司自己又没有开发相应的cms内容管理系统,找了一个星期,综合各方面的考虑,决定选择eyoucms来搭建,经过快速安装,来到了简单干净的后台. 现将使用体会记录如下 ...

  8. day83:luffy:添加购物车&导航栏购物车数字显示&购物车页面展示

    目录 1.添加购物车+验证登录状态 2.右上方购物车图标的小红圆圈数字 3.Vuex 4.购物车页面展示-后端接口 5.购物车页面展示-前端 6.解决一个购物车数量显示混乱的bug 1.添加购物车+验 ...

  9. php拓展 swoole 安装

    1.git clone https://gitee.com/swoole/swoole.git 2.cd swoole 3./usr/local/php7/bin/phpize 4../configu ...

  10. ubuntu 18.04 安装anaconda

    ubuntu 安装anaconda 4版本 为了学习 tensorflow python3.5 版本 使用anaconda 安装: https://mirrors.tuna.tsinghua.edu. ...