江门住房与城乡建设局官方网站,网站代码查询,个人开发者,视频直播平台Netty源码分析第5章(ByteBuf)----第5节: directArena分配缓冲区概述 Netty源码分析第五章: ByteBuf 第五节: directArena分配缓冲区概述 上一小节简单分析了PooledByteBufAllocator中, 线程局部缓存和arean的相关逻辑, 这一小节简单分析下directArena分配缓冲区的相关过程 … Netty源码分析第5章(ByteBuf)----第5节: directArena分配缓冲区概述 Netty源码分析第五章: ByteBuf 第五节: directArena分配缓冲区概述 上一小节简单分析了PooledByteBufAllocator中, 线程局部缓存和arean的相关逻辑, 这一小节简单分析下directArena分配缓冲区的相关过程 回到newDirectBuffer中: protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {PoolThreadCache cache threadCache.get();PoolArenaByteBuffer directArena cache.directArena;ByteBuf buf;if (directArena ! null) { buf directArena.allocate(cache, initialCapacity, maxCapacity);} else {if (PlatformDependent.hasUnsafe()) {buf UnsafeByteBufUtil.newUnsafeDirectByteBuf(this, initialCapacity, maxCapacity);} else {buf new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);}}return toLeakAwareBuffer(buf);
} 获取了directArena对象之后, 通过allocate方法分配一个ByteBuf, 这里allocate方法是PoolArena类中的方法 跟到allocate方法中: PooledByteBufT allocate(PoolThreadCache cache, int reqCapacity, int maxCapacity) { PooledByteBufT buf newByteBuf(maxCapacity); allocate(cache, buf, reqCapacity);return buf;
} 首先通过newByteBuf获得一个ByteBuf对象 再通过allocate方法进行分配, 这里要注意, 这里进行分配的时候是线程私有的directArena进行分配 我们跟到newByteBuf方法中 因为是directArena调用的newByteBuf, 所以这里会进入DirectArena类的newByteBuf中: protected PooledByteBufByteBuffer newByteBuf(int maxCapacity) { if (HAS_UNSAFE) { return PooledUnsafeDirectByteBuf.newInstance(maxCapacity);} else {return PooledDirectByteBuf.newInstance(maxCapacity);}
} 因为默认通常是有unsafe对象的, 所以这里会走到这一步中PooledUnsafeDirectByteBuf.newInstance(maxCapacity) 通过静态方法newInstance创建一个PooledUnsafeDirectByteBuf对象 跟到newInstance方法中: static PooledUnsafeDirectByteBuf newInstance(int maxCapacity) {PooledUnsafeDirectByteBuf buf RECYCLER.get();buf.reuse(maxCapacity);return buf;
} 这里通过RECYCLER.get()这种方式拿到一个ByteBuf对象, RECYCLER其实是一个对象回收站, 这部分内容会在后面的内容中详细剖析, 这里我们只需要知道, 这种方式能从回收站中拿到一个对象, 如果回收站里没有相关对象, 则创建一个新 因为这里有可能是从回收站中拿出的一个对象, 所以通过reuse进行复用 跟到reuse方法中: final void reuse(int maxCapacity) {maxCapacity(maxCapacity);setRefCnt(1);setIndex0(0, 0);discardMarks();
} 这里设置了的最大可扩容内存, 对象的引用数量, 读写指针位置都重置为0, 以及读写指针的位置标记也都重置为0 我们回到PoolArena的allocate方法中: PooledByteBufT allocate(PoolThreadCache cache, int reqCapacity, int maxCapacity) { PooledByteBufT buf newByteBuf(maxCapacity); allocate(cache, buf, reqCapacity);return buf;
} 拿到了ByteBuf对象, 就可以通过allocate(cache, buf, reqCapacity)方法进行内存分配了 跟到allocate方法中: private void allocate(PoolThreadCache cache, PooledByteBufT buf, final int reqCapacity) {//规格化final int normCapacity normalizeCapacity(reqCapacity);if (isTinyOrSmall(normCapacity)) { int tableIdx;PoolSubpageT[] table;//判断是不是tintyboolean tiny isTiny(normCapacity);if (tiny) { // 512//缓存分配if (cache.allocateTiny(this, buf, reqCapacity, normCapacity)) {return;}//通过tinyIdx拿到tableIdxtableIdx tinyIdx(normCapacity);//subpage的数组table tinySubpagePools;} else {if (cache.allocateSmall(this, buf, reqCapacity, normCapacity)) {return;}tableIdx smallIdx(normCapacity);table smallSubpagePools;}//拿到对应的节点final PoolSubpageT head table[tableIdx];synchronized (head) {final PoolSubpageT s head.next;//默认情况下, head的next也是自身if (s ! head) {assert s.doNotDestroy s.elemSize normCapacity;long handle s.allocate();assert handle 0;s.chunk.initBufWithSubpage(buf, handle, reqCapacity);if (tiny) {allocationsTiny.increment();} else {allocationsSmall.increment();}return;}}allocateNormal(buf, reqCapacity, normCapacity);return;}if (normCapacity chunkSize) {//首先在缓存上进行内存分配if (cache.allocateNormal(this, buf, reqCapacity, normCapacity)) {//分配成功, 返回return;}//分配不成功, 做实际的内存分配allocateNormal(buf, reqCapacity, normCapacity);} else {//大于这个值, 就不在缓存上分配allocateHuge(buf, reqCapacity);}
} 这里看起来逻辑比较长, 其实主要步骤分为两步 1.首先在缓存上进行分配, 对应步骤是: cache.allocateTiny(this, buf, reqCapacity, normCapacity) cache.allocateSmall(this, buf, reqCapacity, normCapacity) cache.allocateNormal(this, buf, reqCapacity, normCapacity) 2.如果在缓存上分配不成功, 则实际分配一块内存, 对应步骤是 allocateNormal(buf, reqCapacity, normCapacity) 在这里对几种类型的内存进行介绍: 之前的小节我们介绍过, 缓冲区内存类型分为tiny, small, 和normal, 其实还有种不常见的类型叫做huge, 那么这几种类型的内存有什么区别呢, 实际上这几种类型是按照缓冲区初始化空间的范围进行区分的, 具体区分如下: tiny类型对应的缓冲区范围为0-512B small类型对应的缓冲区范围为512B-8K normal类型对应的缓冲区范围为8K-16MB huge类型对应缓冲区范围为大于16MB 简单介绍下有关范围的含义: 16MB对应一个chunk, netty是以chunk为单位向操作系统申请内存的 8k对应一个page, page是将chunk切分后的结果, 一个chunk对应2048个page 8k以下对应一个subpage, subpage是page的切分, 一个page可以切分多个subpage, 具体切分几个需要根据subpage的大小而定, 比如只要分配1k的缓冲区, 则会将page切分成8个subpage 以上就是directArena内存分配的大概流程和相关概念 上一节: PooledByteBufAllocator简述 下一节: 命中缓存的分配 posted on 2019-01-01 18:32 向南是个万人迷 阅读(...) 评论(...) 编辑 收藏 转载于:https://www.cnblogs.com/xiangnan6122/p/10205478.html