Netty源码解析-池化内存管理解析
Netty版本:4.1.72.Final
Netty当下最热火最热门的网络编程框架需要处理海量的字节数据。Netty提供了字节池化的机制。对象池化内存分配,使用完成后归给内存次。池化内存,那么内存的管理必不可少。Netty基于jemalloc 实现了一套内存分配和管理的机制。
GitHub地址:https://github.com/jemalloc/jemalloc
4.1.72.Final 版本基于 jemalloc4 实现
借鉴 jemalloc
用来解决两个问题:
- 多线程下的内存回收与分配
- 内存的碎片化问题(不断分配和回收过程中会产生,jemalloc4 进一步优化了内存碎片产生)
1. Netty中内存的规格
如上图所示Netty中内存规格分为三类(SizeClass中定义了):
enum SizeClass {
Small,
Normal
}
Tiny现在已经去掉
- small:0-28K(包含)
- normal: 28K(不包含)-16M(包含)
- Huge: 大于16M(不会进行池化)
Hotspot虚拟机的自动内存管理系统要求对象起始地址必须是8字节的整数倍,换句话说就是对象的大小必须是8字节的整数倍。而对象头部分正好是8字节的倍数(1倍或2倍),因此,当对象实例数据部分没有对齐时,就需要通过对齐填充来补全。
Netty的内存管理实现借鉴了 jemalloc
所以很多概念和 jemalloc
中的概念相同。
- Chunk:Netty 向操作系统申请内存的最小单位(默认值16M),是Run的集合
- Run: 对应一块连续的内存,大小是Page的倍数
- Page: Chunk的最小分配单元,默认大小为8K,一个Chunk默认有2K个Page.
- Subpage: 负责Page内的内存分配,目的是为了减少内存的浪费。如果需要分配的内存小于Page的大小(8K)比如只有100B,如果直接分配一个Page(8K)那就直接浪费了。Subpage的最小是16B的倍数。Subpage没有固定的大小,需要根据用户分配的缓冲区决定。
2. Netty内存池的数据结构
通过图可以知道,Netty根据内存模型抽象出来了一些组件, PoolArena、PoolChunk、PoolChunkList、PoolSubpage、PoolThreadCache、MemoryRegionCache
下面根据不同模块结合代码逐一分析其数据结构和实现。
Tips:很多概念和jemalloc中的概念相似大同小异,当前研究的代码版本中取消了网上很多资料里面出现的内存规格
tiny
类型。只有 small、normal、huge, 具体是因为当前的版本的Netty内存分配实现是基于jemalloc4
。