概述

文章主要介绍的是PoolArena,PoolChunk,PoolSubpage 三个类的源码

PoolArena

PoolArena 是netty 的内存池实现类,通过预先申请一块大的空间,然后对空间进行分配和回收,这样就不用频繁进行系统调用,提高性能。
PoolArena 由多个 chunk 组成,chunk 则由多个page 组成.

PoolChunk

Chunk 主要用来组织和管理多个Page的内存分配和释放,在netty中,Chunk 中的Page被构造成一棵二叉树。

PoolSubpage

PoolSubpage保存long[] 数组表示占用情况。数组中一个long元素最多表示64分空间的占用情况,假如某块空间分的分数多于64份,那么数组中加多一个元素,例如4字节分4份,long元素的第四位就可以表示完,要是128字节分128份,long数组就要添加多一个元素共2个元素,一个long表示64份。

内存回收策略

  • chunk 回收 : 二叉树节点状态标识符
  • page 回收 : 维护块的使用状态来标识

源码

上面就是我们刚才讲的几个类的类结构。
final class PoolSubpage<T> {

	//保持一个 PoolChunk
final PoolChunk<T> chunk;
final int memoryMapIdx;
final int runOffset;
final int pageSize;
final long[] bitmap; //前后指针
PoolSubpage<T> prev;
PoolSubpage<T> next; boolean doNotDestroy;
int elemSize;
int maxNumElems;
int nextAvail;
int bitmapLength;
int numAvail; // TODO: Test if adding padding helps under contention
//private long pad0, pad1, pad2, pad3, pad4, pad5, pad6, pad7; /** Special constructor that creates a linked list head */
PoolSubpage(int pageSize) {
chunk = null;
memoryMapIdx = -1;
runOffset = -1;
elemSize = -1;
this.pageSize = pageSize;
bitmap = null;
} ...
final class PoolChunkList<T> {
private final PoolArena<T> arena;
//前后指针
private final PoolChunkList<T> nextList;
PoolChunkList<T> prevList; ...
}
abstract class PoolArena<T> {

    final PooledByteBufAllocator parent;

    private final int pageSize;
private final int maxOrder;
private final int pageShifts;
private final int chunkSize;
private final int subpageOverflowMask; private final PoolSubpage<T>[] tinySubpagePools;
private final PoolSubpage<T>[] smallSubpagePools; private final PoolChunkList<T> q050;
private final PoolChunkList<T> q025;
private final PoolChunkList<T> q000;
private final PoolChunkList<T> qInit;
private final PoolChunkList<T> q075;
private final PoolChunkList<T> q100; // TODO: Test if adding padding helps under contention
//private long pad0, pad1, pad2, pad3, pad4, pad5, pad6, pad7; protected PoolArena(PooledByteBufAllocator parent, int pageSize, int maxOrder, int pageShifts, int chunkSize) {
this.parent = parent;
this.pageSize = pageSize;
this.maxOrder = maxOrder;
this.pageShifts = pageShifts;
this.chunkSize = chunkSize;
subpageOverflowMask = ~(pageSize - 1); tinySubpagePools = newSubpagePoolArray(512 >>> 4);
for (int i = 0; i < tinySubpagePools.length; i ++) {
tinySubpagePools[i] = newSubpagePoolHead(pageSize);
} smallSubpagePools = newSubpagePoolArray(pageShifts - 9);
for (int i = 0; i < smallSubpagePools.length; i ++) {
smallSubpagePools[i] = newSubpagePoolHead(pageSize);
} q100 = new PoolChunkList<T>(this, null, 100, Integer.MAX_VALUE);
q075 = new PoolChunkList<T>(this, q100, 75, 100);
q050 = new PoolChunkList<T>(this, q075, 50, 100);
q025 = new PoolChunkList<T>(this, q050, 25, 75);
q000 = new PoolChunkList<T>(this, q025, 1, 50);
qInit = new PoolChunkList<T>(this, q000, Integer.MIN_VALUE, 25); q100.prevList = q075;
q075.prevList = q050;
q050.prevList = q025;
q025.prevList = q000;
q000.prevList = null;
qInit.prevList = qInit;
} ....

源码分析 PooledDirectByteBuf

开始看 PooledDirectByteBuf 的方法有点乱,我们可以从调用它的那个类开始分析。 PooledByteBufAllocator内部就是可以调用 PooledDirectByteBuf 生成 ByteBuf的类。它的使用如下 :

    public static void main(String[] args){
/*
* 内存池buffer 提供为外部的使用主要是通过 PooledByteBufAllocator 这个类堆外提供
*/
PooledByteBufAllocator allocator = new PooledByteBufAllocator();
ByteBuf directBuffer = allocator.directBuffer();
}
下面我们看一下 directBuffer 方法。
    @Override
public ByteBuf directBuffer() {
return directBuffer(DEFAULT_INITIAL_CAPACITY, Integer.MAX_VALUE);
} @Override
public ByteBuf directBuffer(int initialCapacity, int maxCapacity) {
if (initialCapacity == 0 && maxCapacity == 0) {
return emptyBuf;
}
//校验
validate(initialCapacity, maxCapacity);
//子类实现,申请空间
return newDirectBuffer(initialCapacity, maxCapacity);
} // PooledByteBufAllocator 类中的实现
@Override
protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
//No.1 缓冲中获取
PoolThreadCache cache = threadCache.get();
PoolArena<ByteBuffer> directArena = cache.directArena; ByteBuf buf;
if (directArena != null) {
buf = directArena.allocate(cache, initialCapacity, maxCapacity);
} else {
//假如缓冲中的 PoolArena 不存在
if (PlatformDependent.hasUnsafe()) {
buf = new UnpooledUnsafeDirectByteBuf(this, initialCapacity, maxCapacity);
} else {
buf = new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);
}
} return toLeakAwareBuffer(buf);
} // PooledByteBufAllocator 类中的threadCache ,是个ThreadLocal
final ThreadLocal<PoolThreadCache> threadCache = new ThreadLocal<PoolThreadCache>() {
private final AtomicInteger index = new AtomicInteger();
@Override
protected PoolThreadCache initialValue() {
final int idx = index.getAndIncrement();
final PoolArena<byte[]> heapArena;
final PoolArena<ByteBuffer> directArena; if (heapArenas != null) {
heapArena = heapArenas[Math.abs(idx % heapArenas.length)];
} else {
heapArena = null;
} if (directArenas != null) {
directArena = directArenas[Math.abs(idx % directArenas.length)];
} else {
directArena = null;
} return new PoolThreadCache(heapArena, directArena);
}
};

参考资料

  • 《netty权威指南》

netty(七)buffer源码学习2的更多相关文章

  1. netty(八)buffer源码学习3

    问题 : compositeByteBuf 是干什么和其他 compositeByteBuf 有何区别 内部实现 概述 compositeByteBuf 就像数据库中的视图,把几个表的字段组合在一起, ...

  2. netty(六) buffer 源码分析

    问题 : netty的 ByteBuff 和传统的ByteBuff的区别是什么? HeapByteBuf 和 DirectByteBuf 的区别 ? HeapByteBuf : 使用堆内存,缺点 ,s ...

  3. 【Netty源码学习】DefaultChannelPipeline(三)

    上一篇博客中[Netty源码学习]ChannelPipeline(二)我们介绍了接口ChannelPipeline的提供的方法,接下来我们分析一下其实现类DefaultChannelPipeline具 ...

  4. 【Netty源码学习】ChannelPipeline(一)

    ChannelPipeline类似于一个管道,管道中存放的是一系列对读取数据进行业务操作的ChannelHandler. 1.ChannelPipeline的结构图: 在之前的博客[Netty源码学习 ...

  5. 【Netty源码学习】ServerBootStrap

    上一篇博客[Netty源码学习]BootStrap中我们介绍了客户端使用的启动服务,接下来我们介绍一下服务端使用的启动服务. 总体来说ServerBootStrap有两个主要功能: (1)调用父类Ab ...

  6. Netty 源码学习——EventLoop

    Netty 源码学习--EventLoop 在前面 Netty 源码学习--客户端流程分析中我们已经知道了一个 EventLoop 大概的流程,这一章我们来详细的看一看. NioEventLoopGr ...

  7. Netty 源码学习——客户端流程分析

    Netty 源码学习--客户端流程分析 友情提醒: 需要观看者具备一些 NIO 的知识,否则看起来有的地方可能会不明白. 使用版本依赖 <dependency> <groupId&g ...

  8. Netty源码学习系列之4-ServerBootstrap的bind方法

    前言 今天研究ServerBootstrap的bind方法,该方法可以说是netty的重中之重.核心中的核心.前两节的NioEventLoopGroup和ServerBootstrap的初始化就是为b ...

  9. Netty源码学习(零)前言

    本系列文章将介绍Netty的工作机制,以及分析Netty的主要源码. 基于的版本是4.1.15.Final(2017.08.24发布) 水平有限,如有谬误请留言指正 参考资料 the_flash的简书 ...

随机推荐

  1. Vue开发重点基础知识

    1.Vuejs组件 vuejs构建组件使用 Vue.component('componentName',{ /*component*/ }): 这里注意一点,组件要先注册再使用,也就是说: Vue.c ...

  2. webrtc博客收藏

    <使用WebRTC搭建前端视频聊天室——入门篇><使用WebRTC搭建前端视频聊天室——信令篇><使用WebRTC搭建前端视频聊天室——点对点通信篇><使用W ...

  3. 执行yum相关命令总是卡住,ctrl+c也退出不了

    问题描述 在用yum.rpm命令安装或查询任何包时,执行相关命令后无任何反应,直接卡住,也未给出任何错误提示信息,ctrl+c也不好使,只能杀掉进程. 原因 出现此问题是因为rpm的数据库出现异常了, ...

  4. ConsoleWindow中的双击日志定位

    很多项目都有自己重写Debug.Log的习惯,难免会遇到在Unity的Console窗口中双击日志, 但是没法直接跳转到想要看到的代码那一行的时候,解决办法有以下2种: 将自己封装的日志类制作成DLL ...

  5. DataFrames,Datasets,与 SparkSQL

    v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} w\:* {behavior:url(#default#VM ...

  6. MySQL学习(十一)double write 介绍 (半原创)

    复习 Innodb关键的特性 插入缓存 两次写 异步IO 刷新邻近页 自适应哈希索引 概述 double write 的主要的作用是保证写入数据库文件的可靠性.通俗地说就是一份数据写两个地方,当出现异 ...

  7. 516,base64的原理及优缺点

    优点是可以加密,减少了http请求 缺点是需要消耗cpu进行编解码 适用于小图片 base的体积约为原图的4/3

  8. 转载:DRC

    https://cn.mathworks.com/help/audio/ug/dynamic-range-control.html?requestedDomain=cn.mathworks.com h ...

  9. codeforces 1204C Anna, Svyatoslav and Maps(floyd+dp)

    题目链接:http://codeforces.com/problemset/problem/1204/C 给定一组序列,P1,P2,P3...Pm,这是一组合法路径的序列,即任意的Pi和Pi+1之间有 ...

  10. html中的路径详解

    路径指文件存放的位置,在网页中利用路径可以引用文件,插入图像.视频等.表示路径的方法有两种:相对路径,绝对路径.以下讨论均是在HTML环境下进行. 相对路径 相对路径是指目标相对于当前文件的路径,网页 ...