本章介绍netty的另一个核心知识点,就是关于netty内存实现的原理机制,主要从它的功能,内存池以及实现功能:

功能:避免频繁的内存分配给系统带来负担以及GC对系统性能带来波动

内存池:

& slab分配

>>内存分割成大小不等的内存块,用户线程请求内存时根据请求的内存大小分配最贴近size的内存块

>>在减少内存碎片的同时又能很好的避免内存浪费

& buddy分配

>>把一些内存块等量分割,回收时合并,尽可能保证系统中有足够大的连续内存

& 堆内存和非堆内存

分配区分类:

& 线程私有分配区

>>当内存被分配给某个线程之后,在释放内存时释放的内存不会直接返回给公有分配区,而是直接在线程私有分配区中缓存

>>当线程频繁的申请内存时会提高分配效率

& 内存池公有分配区

>>同时当线程申请内存的动作不活跃时可能会造成内存浪费的情况,这时候内存池会对线程私有分配区中的情况进行监控

>>当发现线程的分配活动并不活跃时会把线程缓存的内存块释放返回给公有区

& jvm分配区

>>在整个内存分配时可能会出现分配的内存过大导致内存池无法分配的情况,这时候就需要JVM堆直接分配

分配机制:

& 线程私有分配

PoolThreadCache
>>tinySubPageHeapCaches:tiny
>>smallSubPageHeapCaches:small
>>normalHeapCaches:normall

& 全局分配

>>内存池的初始阶段,线程是没有内存缓存的,所以最开始的内存分配都需要在全局分配区进行分配

Netty的实现流程:

PooledByteBufAllocator:调用PoolArena实现内存池分配

PoolArena:

& PoolChunkList(封装PoolChunk)
>>qInit:存储剩余内存0-25%的chunk
>>q000:存储剩余内存1-50%的chunk
>>q025:存储剩余内存25-75%的chunk
>>q050:存储剩余内存50-100%个chunk
>>q075:存储剩余内存75-100%个chunk
>>q100:存储剩余内存100%chunk
& PoolChunk(内存块)
>>chunkSize=pageSize*(2的maxOrder次幂)
>>maxOrder可以通过io.netty.allocator.maxOrder系统变量设置
>>只能设置0-14范围内的值,默认值11
& PoolSubpage(内存页)
>>io.netty.allocator.pageSize:默认8192即8K
>>这个pageSize大小不是随意设置是有限制的,它必须大于4096(4K)
>>必须是2的整数次幂

算法流程:

请求的内存大小是否超过了chunkSize

& 超过

>>内存内存池无法分配应由JVM分配,直接返回原始大小

& 未超过

>>请求大小大于等于512

>>>大小在[512,pageSize]

>>>返回一个512的2次幂倍数当做最终的内存大小

>>请求大小小于512:返回一个16的整数倍:tiny块

>>大小在(pageSize,chunkSize]区间时分配normal块

总结:netty对于内存的管理使用了比较灵活的方式,支持按照不同的申请内存大小而选择对应的内存申请方法,使效率变得更高,本文说的是比较概括,如果想看详细内存分配的话建议看看jemalloc这个知识,因为netty基本使用了这个思想.