概述

文章主要介绍的是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. ansible笔记(12):变量(一)

    1.定义变量规范 先说说怎样定义变量,变量名应该由字母.数字.下划线组成,变量名需要以字母开头,ansible内置的关键字不能作为变量名. 2.定义变量,使用关键字:vars 定义变量用vars,调用 ...

  2. PP: UMAP: uniform manifold approximation and projection for dimension reduction

    From Tutte institute for mathematics and computing Problem: dimension reduction Theoretical foundati ...

  3. not under version control

    表示这个文件没有在SVN的控制之下 你在执行commit操作的时候,只有处于SVN控制之下的文件才能被commit,从update得到的文件是在SVN控制之下的(比如原来就存在的文本文件,你可以对其修 ...

  4. 素问 - REITs

    摘自<小韭的学习圈> Q 一直以来对REITs感兴趣,看过您微信公众号对REITs的分析,年化8-10%,长期收益稳定,且与其他投资品种关键性低,是很不错的分散配置选择. 您推荐的广发美国 ...

  5. JS 数组克隆方法总结

    ES5 方法总结 1.slice let arr = [2,4,434,43] let arr1= arr.slice() arr[0] = 'a' console.log(arr,arr1) // ...

  6. 【14】 DFS 机器人活动范围 (static插曲)

    题目 地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] .一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左.右.上.下移动一格(不能移动到方格外),也不能进入行坐 ...

  7. Ubuntu安装程序报错:无法获得锁 /var/lib/dpkg/lock-frontend - open (11: 资源暂时不可用)

    问题描述:在使用Ubuntu系统时安装程序时出现下面的报错. E: 无法获得锁 /var/lib/dpkg/lock-frontend - open (11: 资源暂时不可用)E: Unable to ...

  8. Customized Mini LED Keychain For Better Brand Identity

    Looking for products that tell people the brand name? Then you'll find an affordable product that wi ...

  9. 8.10-Day1T2圈(circle)

    圈(circle) 题目大意 一开始看这道题,觉得有点像备用钥匙那道题,需要离散化, 把一个球的两个点分开看... 但是..其中的规律我推不出来 (不是很难,只是蒟蒻好久都没有自己独立思考了) 题解 ...

  10. Lenet 神经网络-实现篇(1)

    Lenet 神经网络结构为: ①输入为 32*32*1 的图片大小,为单通道的输入: ②进行卷积,卷积核大小为 5*5*1,个数为 6,步长为 1,非全零填充模式: ③将卷积结果通过非线性激活函数: ...