动态分配
系列篇将动态分配分成上下两篇,本篇为下篇,阅读之前建议翻看上篇。
- 鸿蒙内核源码分析(TLFS算法) 结合图表从理论视角说清楚 TLFS 算法
- 鸿蒙内核源码分析(内存池管理) 结合源码说清楚鸿蒙内核动态内存池实现过程,个人认为这部分代码很精彩,简洁高效,尤其对空闲节点和已使用节点的实现令人称奇。
为了便于理解源码,站长画了以下图,图中列出主要结构体,位图,分配和释放信息,逐一说明。
- 请将内存池想成一条画好了网格虚线的大白纸,会有两种角色往白纸上画东西,一个是内核画管理数据,一个外部程序画业务数据,内核先画,外部程序想画需申请大小,申请成功内核会提供个地址给外部使用,例如申请
20
个格子,成功后内核返回一个(5,8)
坐标,表示从第五行第八列开始往后的连续20
个格子你可以使用。用完了释放只需要告诉内核一个坐标(5,8)
而不需要大小,内核就知道回收多少格子。但内核凭什么知道要释放多少个格子呢 ? 一定有个格子给记录下来了对不对,实际中存大小的格子坐标就是(5,7)
。其值是在申请的时候或更早的时候填进去的。而且不一定是20
,但一定不小于20
。如果您能完全理解以上这段话,那可能已经理解了内存池的管理的方式,不用往下看了。
内存池 | OsMemPoolHead
/// 内存池头信息
struct OsMemPoolHead {
struct OsMemPoolInfo info; ///< 记录内存池的信息
UINT32 freeListBitmap[OS_MEM_BITMAP_WORDS]; ///< 空闲位图 int[7] = 32 * 7 = 224
struct OsMemFreeNodeHead *freeList[OS_MEM_FREE_LIST_COUNT];///< 空闲节点链表 32 + 24 * 8 = 224
SPIN_LOCK_S spinlock; ///< 操作本池的自旋锁,涉及CPU多核竞争,所以必须得是自旋锁
#ifdef LOSCFG_MEM_MUL_POOL
VOID *nextPool; ///< 指向下一个内存池 OsMemPoolHead 类型
#endif
};
/// 内存池信息
struct OsMemPoolInfo {
VOID *pool; ///< 指向内存块基地址,仅做记录而已,真正的分配内存跟它没啥关系
UINT32 totalSize; ///< 总大小,确定了内存池的边界
UINT32 attr; ///< 属性 default attr: lock, not expand.
#ifdef LOSCFG_MEM_WATERLINE
UINT32 waterLine; /* Maximum usage size in a memory pool | 内存吃水线*/
UINT32 curUsedSize; /* Current usage size in a memory pool | 当前已使用大小*/
#endif
};
解读
-
OsMemPoolInfo.pool
是整个内存池的第一个格子,里面放的是一个内存池起始虚拟地址。 -
OsMemPoolInfo.totalSize
表示这张纸有多少个格子。 -
OsMemPoolInfo.attr
表示池子还能不能再变大。 -
OsMemPoolInfo.waterLine
池子水位警戒线,跟咱三峡大坝发洪水时的警戒线 175米 类似,告知上限,水一旦漫过此线就有重大风险,waterLine
一词很形象,内核很多思想真来源于生活。 -
OsMemPoolInfo.curUsedSize
所有已分配内存大小的叠加。 -
freeListBitmap
空闲位图,这是tlfs
算法的一二级表示,是个长度为7
的整型数组#define OS_MEM_BITMAP_WORDS ((OS_MEM_FREE_LIST_COUNT >> 5) + 1) #define OS_MEM_FREE_LIST_COUNT (OS_MEM_SMALL_BUCKET_COUNT + (OS_MEM_LARGE_BUCKET_COUNT << OS_MEM_SLI)) #define OS_MEM_LARGE_START_BUCKET 7 /// 大桶的开始下标 #define OS_MEM_SMALL_BUCKET_COUNT 31 ///< 小桶的偏移单位 从 4 ~ 124 ,共32级 #define OS_MEM_SLI 3 ///< 二级小区间级数,
这一坨坨的宏看着有点绕,简单说就是鸿蒙对申请大小分成两种情况
- 第一种:小桶申请** 当小于128个字节大小的需求平均分成了
([0-4],[4-8],...,[124-128])
共32
个等级,而freeListBitmap[0]
为一个UINT32
,共32
位刚好表示这32
- 第一种:小桶申请** 当小于128个字节大小的需求平均分成了