[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](http://pic.ttrar.cn/nice/%5bNetty%e6%ba%90%e7%a0%81%5dBy.jpg)
文章目录
-
-
- 1.ByteBufAllocator 内存管理器
- 2.UnpooledByteBufAllocator
-
- 2.1 heap内存的分配
- 2.2 direct内存的分配
- 3.PooledByteBufAllocator
-
- 3.1 heap内存和direct内存的分配
- 3.2 directArena分配direct内存的流程
- 3.3 内存规格的介绍
- 4.缓存的相关问题
-
- 4.1 缓存的数据结果
- 4.2 命中缓存的分配流程
- 5.PoolThreadCache的相关问题
-
- 5.1 Arena数据结构分析
- 5.2 Page级别的内存分配
- 5.3 Subpage级别的内存分配
-
1.ByteBufAllocator 内存管理器
ByteBuf分类:
- pooled和unpooled
- heap和direct
- unsafe和非unsafe
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/1131d5601974442d8c5d34169c3f0c50.png)
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/f82bc1b356464b2baee52932bec984b2.png)
通过不同的方法去读取到数据。
@Overridepublic ByteBuf buffer() {if (directByDefault) {return directBuffer();}return heapBuffer();}
堆内存分类
@Overridepublic ByteBuf heapBuffer() {return heapBuffer(DEFAULT_INITIAL_CAPACITY, DEFAULT_MAX_CAPACITY);}@Overridepublic ByteBuf heapBuffer(int initialCapacity, int maxCapacity) {if (initialCapacity == 0 && maxCapacity == 0) {return emptyBuf;}validate(initialCapacity, maxCapacity);return newHeapBuffer(initialCapacity, maxCapacity);}
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/3d4effafa06146ea8e9c7dcf5a07b84a.png)
- PooledByteBufAllocator: 通过在预先分配好的内存中分配数据
- UnpooledByteBufAllocator: 从操作系统中直接分配内存数据
2.UnpooledByteBufAllocator
- newHeapBuffer
- newDirectBuffer
2.1 heap内存的分配
UnpooledByteBufAllocator.newHeapBuffer()
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/78df9cca33274e76a54f9355338076f5.png)
判断是否是Unsafe, 如果有Unsafe的辅助, 为InstrumentedUnpooledUnsafeHeapByteBuf, 如果没有则为InstrumentedUnpooledHeapByteBuf
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/d36e823cca6d499db5f523db9ddec3d3.png)
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/3d1141163b3a40b7981bba28c36eb630.png)
一个是UnpooledUnsafeHeapByteBuf, 一个是UnpooledHeapByteBuf, 不过UnpooledUnsafeHeapByteBuf是继承UnpooledHeapByteBuf的
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/a415de3bc9ff44f190ec21545f469be3.png)
UnpooledUnsafeHeapByteBuf
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/554d19d61d1346cdbfd9ffdf1f069ed5.png)
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/c50118e7aa2d45afb4cca1facd4f91fb.png)
这里的UnpooledUnsafeHeapByteBuf和UnpooledHeapByteBuf区别在于_getByte()以及一些类似的方法, 区别在于工具类的使用上
UnpooledUnsafeHeapByteBuf
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/753ea4ed86124d9f8e0bd31bd6686a0d.png)
UnpooledHeapByteBuf
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/69b916d5f3dd49009c52e0f4bb608d0d.png)
一个是UnsafeByteBufUtil, 一个是HeapByteBufUtil
UnsafeByteBufUtil
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/81f6ad511b2840188255b0f7baf9d0f9.png)
HeapByteBufUtil
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/9f2f04118c7147c594f339d4548c803f.png)
UnsafeByteBufUtil是通过对象加偏移量的方式获取数据的, 而HeapByteBufUtil是通过数组获取数据的。前一种的效率高一些。
2.2 direct内存的分配
UnpooledByteBufAllocator.newDirectBuffer()
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/39596fdae5c442e192bac3c548b6975a.png)
- InstrumentedUnpooledDirectByteBuf: UnpooledDirectByteBuf
- InstrumentedUnpooledUnsafeDirectByteBuf: UnpooledUnsafeDirectByteBuf
- InstrumentedUnpooledUnsafeNoCleanerDirectByteBuf: UnpooledUnsafeNoCleanerDirectByteBuf, UnpooledUnsafeDirectByteBuf
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/4bc09a3b5f804e88850fe8367fe2aedd.png)
UnpooledDirectByteBuf
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/3eb89b780da44e5b97a0a1cb6ce9b370.png)
UnpooledDirectByteBuf.setByteBuffer()
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/34a2a760da2240d0b85004968a0c3495.png)
UnpooledUnsafeDirectByteBuf.setByteBuffer()
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/6b996c9b91dc46d18d33079772cf77c9.png)
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/47cca885812548d7b737062758f53114.png)
先是调用了子类的方法, 然后调用Unsafe拿到对应的数据。
其次是_getByte()等方法的不同, Unsafe会通过一个内存地址加偏移量获取数据, 非unsafe通过数组下标获取数据的。
3.PooledByteBufAllocator
- newDirectBuffer
- newHeapBuffer
3.1 heap内存和direct内存的分配
private final PoolThreadLocalCache threadCache;@Overrideprotected ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity) {// 获取线程局部缓存PoolThreadCachePoolThreadCache cache = threadCache.get();// 从局部缓存中获取到heap竞技场部分 PoolArena<byte[]> heapArena = cache.heapArena;final ByteBuf buf;if (heapArena != null) {// 主要的进行分配的过程buf = heapArena.allocate(cache, initialCapacity, maxCapacity);} else {buf = PlatformDependent.hasUnsafe() ?new UnpooledUnsafeHeapByteBuf(this, initialCapacity, maxCapacity) :new UnpooledHeapByteBuf(this, initialCapacity, maxCapacity);}return toLeakAwareBuffer(buf);}
- 获取线程局部缓存PoolThreadCache, 从PoolThreadLocalCache 获取到
- 从局部缓存中获取到heap竞技场部分PoolArena
- 从Arena上进行内存分配
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/3017b0de002a49f0a327e3b65e4a786e.png)
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/6d9d534e39c4471a8776350130400b58.png)
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/4dae2a8b72864edbbabed98683884ccb.png)
这里的nDirectArena为2倍的cpu核数, 为的是之前创建的NioEventLoop的数量对应
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/98ae578398e24248a707c133e977dab6.png)
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/bedca4815af340cf8371202dfd2876b1.png)
PooledByteBufAllocator的结构, 每一个Thread和Area对应, 都是2倍Cpu核数
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/56a37d7400164d94ad47632de7da982e.png)
线程局部缓存PoolThreadCache
- tinyCacheSize
- smallCacheSize
- normalCacheSize
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/07af3700ba244a80b53acf2652dbc53b.png)
3.2 directArena分配direct内存的流程
directArena.allocate(cache, initialCapacity, maxCapacity)
- 从对象池中获取PooledByteBuf进行复用
- 从缓存上进行内存分配
- 从内存堆中进行内存分配
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/d49ab8afae1f434aa132b507ede223d6.png)
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/59cf2164e60e40f4a5f0d8d12a1cabad.png)
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/f8e97dc780494e379e4d2aa010c5fff3.png)
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/8f6c5ef72958488e89747f8b65c8fbcc.png)
- Unsafe: PooledUnsafeDirectByteBuf
- 非Unsafe: PooledDirectByteBuf
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/498cf605755c4b179073fcb3dbafd8ad.png)
- 轻量级对象池获取ByteBuf
- ByteBuf复用方法
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/61c3bc638e86432992239d0bcfb1cdd6.png)
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/f54036d126a9448db4063b7adc701d87.png)
allocate()
分配内存逻辑
private void allocate(PoolThreadCache cache, PooledByteBuf<T> buf, final int reqCapacity) {final int normCapacity = normalizeCapacity(reqCapacity);if (isTinyOrSmall(normCapacity)) { // capacity < pageSizeint tableIdx;PoolSubpage<T>[] table;boolean tiny = isTiny(normCapacity);if (tiny) { // < 512if (cache.allocateTiny(this, buf, reqCapacity, normCapacity)) {// was able to allocate out of the cache so move onreturn;}tableIdx = tinyIdx(normCapacity);table = tinySubpagePools;} else {if (cache.allocateSmall(this, buf, reqCapacity, normCapacity)) {// was able to allocate out of the cache so move onreturn;}tableIdx = smallIdx(normCapacity);table = smallSubpagePools;}final PoolSubpage<T> head = table[tableIdx];/* Synchronize on the head. This is needed as {@link PoolChunk#allocateSubpage(int)} and* {@link PoolChunk#free(long)} may modify the doubly linked list as well.*/synchronized (head) {final PoolSubpage<T> s = head.next;if (s != head) {assert s.doNotDestroy && s.elemSize == normCapacity;long handle = s.allocate();assert handle >= 0;s.chunk.initBufWithSubpage(buf, null, handle, reqCapacity);incTinySmallAllocation(tiny);return;}}synchronized (this) {allocateNormal(buf, reqCapacity, normCapacity);}incTinySmallAllocation(tiny);return;}if (normCapacity <= chunkSize) {if (cache.allocateNormal(this, buf, reqCapacity, normCapacity)) {// was able to allocate out of the cache so move onreturn;}synchronized (this) {allocateNormal(buf, reqCapacity, normCapacity);++allocationsNormal;}} else {// Huge allocations are never served via the cache so just call allocateHugeallocateHuge(buf, reqCapacity);}}
3.3 内存规格的介绍
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/adac422c8c8645969a97dbb229525c47.png)
- 0 - 512B 为tinySize, 单位为SubPage
- 512B - 8K 为smallSize, 单位为SubPage
- 8K - 16M 为normalSize, 单位为Page
- 16M以上 为hugeSize, 单位为Chunk
4.缓存的相关问题
4.1 缓存的数据结果
MemoryRegionCache
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/bc30e75f80194416a580802ec55d571e.png)
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/5db3f86f5993440c869613ff98dc3046.png)
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/860033c6b81e4cb58ea5bd5248abda62.png)
- queue: chunk handler执行逻辑
- sizeClass: tiny, small, normal
- size: 16B, 512B, 1K, 2K, 4K, 8K, 16K, 32K
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/f75afb599a6c4189bc0b02877bc5967c.png)
- tiny的数组大小为32: 16B - 496B
- small的数组大小为4: 512BM 1K 2K 4K
- normal的数组大小为3: 8K 16K 32K
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/aca32ff5448e44df884eabbc7e3333a1.png)
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/630b7747395d4f5e90404a0b55fd884c.png)
通过计算和传参获取到数组大小和数组的单位的大小
4.2 命中缓存的分配流程
分配内存逻辑中存在名字缓存的分配流程。
private void allocate(PoolThreadCache cache, PooledByteBuf<T> buf, final int reqCapacity) {final int normCapacity = normalizeCapacity(reqCapacity);if (isTinyOrSmall(normCapacity)) { // capacity < pageSizeint tableIdx;PoolSubpage<T>[] table;boolean tiny = isTiny(normCapacity);if (tiny) { // < 512// 命中缓存的分配流程if (cache.allocateTiny(this, buf, reqCapacity, normCapacity)) {// was able to allocate out of the cache so move onreturn;}tableIdx = tinyIdx(normCapacity);table = tinySubpagePools;} else {// 命中缓存的分配流程if (cache.allocateSmall(this, buf, reqCapacity, normCapacity)) {// was able to allocate out of the cache so move onreturn;}tableIdx = smallIdx(normCapacity);table = smallSubpagePools;}final PoolSubpage<T> head = table[tableIdx];/* Synchronize on the head. This is needed as {@link PoolChunk#allocateSubpage(int)} and* {@link PoolChunk#free(long)} may modify the doubly linked list as well.*/synchronized (head) {final PoolSubpage<T> s = head.next;if (s != head) {assert s.doNotDestroy && s.elemSize == normCapacity;long handle = s.allocate();assert handle >= 0;s.chunk.initBufWithSubpage(buf, null, handle, reqCapacity);incTinySmallAllocation(tiny);return;}}synchronized (this) {allocateNormal(buf, reqCapacity, normCapacity);}incTinySmallAllocation(tiny);return;}if (normCapacity <= chunkSize) {if (cache.allocateNormal(this, buf, reqCapacity, normCapacity)) {// was able to allocate out of the cache so move onreturn;}synchronized (this) {allocateNormal(buf, reqCapacity, normCapacity);++allocationsNormal;}} else {// Huge allocations are never served via the cache so just call allocateHugeallocateHuge(buf, reqCapacity);}}
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/b35607fc43cc4e00be798ce4107a5f13.png)
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/8b675df72e474cd68778c95def66e55c.png)
- 找到对应size的MemoryRegionCache
- 从queue中弹出一个entry给ByteBuf初始化
- 将弹出的entry扔到对象池进行复用
找到对应size的MemoryRegionCache
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/fe127aca63634bcaa07314f937972705.png)
从queue中弹出一个entry给ByteBuf初始化
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/85f5817ac9c24ef888a5d204f62b145a.png)
初始化
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/14ac73f9b7f749a188c0b349df94e263.png)
将弹出的entry扔到对象池进行复用
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/b077732a2066449abdf3eccb5066b3bd.png)
5.PoolThreadCache的相关问题
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/7d6bc50958a74b5589082c9473f54fd6.png)
- cache: 之前的MemoryRegionCache
- arena: PoolArena, PoolChunkList, PoolChunk, PoolSubpage
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/41b48f67727d4dd0af6538a4472fd142.png)
5.1 Arena数据结构分析
Arena: ChunkList的双向链表 -> Chunk的双向链表
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/2eaa0c3d53f5400ab062f6a95db8c976.png)
Chunk -> subpage[]数组
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/4623b942ad4e4a049661ebd823751dd7.png)
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/48bb03f0188040bbaea1649b197aeabc.png)
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/8f82bbeb07a74419b99209f718f89de5.png)
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/17698f16a70247b3aef6ff181faa82e1.png)
5.2 Page级别的内存分配
allocateNormal()
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/fe2151a7bdde4589a7627e4f967268ac.png)
- 尝试在现有的chunk上分配
- 创建一个chunk进行分配
- 初始化pooledByteBuf: c.allocate()
创建chunk分配 PoolChunk
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/7f6d2232ca5f478a87d311e3e1a6a180.png)
PoolChunk(PoolArena<T> arena, T memory, int pageSize, int maxOrder, int pageShifts, int chunkSize, int offset) {unpooled = false;this.arena = arena;this.memory = memory;this.pageSize = pageSize;this.pageShifts = pageShifts;this.maxOrder = maxOrder;this.chunkSize = chunkSize;this.offset = offset;unusable = (byte) (maxOrder + 1);log2ChunkSize = log2(chunkSize);subpageOverflowMask = ~(pageSize - 1);freeBytes = chunkSize;assert maxOrder < 30 : "maxOrder should be < 30, but is: " + maxOrder;maxSubpageAllocs = 1 << maxOrder;memoryMap = new byte[maxSubpageAllocs << 1];depthMap = new byte[memoryMap.length];int memoryMapIndex = 1;for (int d = 0; d <= maxOrder; ++ d) { // move down the tree one level at a timeint depth = 1 << d;for (int p = 0; p < depth; ++ p) {// in each level traverse left to right and set value to the depth of subtreememoryMap[memoryMapIndex] = (byte) d;depthMap[memoryMapIndex] = (byte) d;memoryMapIndex ++;}}subpages = newSubpageArray(maxSubpageAllocs);cachedNioBuffers = new ArrayDeque<ByteBuffer>(8);}
handle: 对应chunk中第几个page的第几个subpage, 就是拿到内存里的哪一个连续内存
初始化PooledByteBuf
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/e759dbbcf0c540b480ce4d99346bb865.png)
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/2549b41f309049da8f2438b90543675a.png)
5.3 Subpage级别的内存分配
allocateSubpage()
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/4de9a3138eea4083884251d61fd2d86f.png)
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/3f72532cd2bc4d79b31a3e1c0808aff7.png)
![[Netty源码] ByteBufAllocator内存管理器相关问题 (十一)](https://img-blog.csdnimg.cn/b8146c9d0f284aa68618e3deb89c4290.png)
- 定位到Subpage对象
- 初始化Subpage: 划分page
- 初始化PooledByteBuf: 和page级别的内存分配一个代码


