鸿蒙轻内核M核源码学习 动态内存(1)

举报
HongjinLI 发表于 2021/11/12 20:08:31 2021/11/12
【摘要】 首先,要学习一下大佬关于鸿蒙M核动态内存的系列博客:https://bbs.huaweicloud.com/blogs/279703自己结合代码,理解一下底层的基本原理。一、关于TLSF算法TLSF是一个动态内存的分配算法,通过以下两篇文章可以对此有一个大概的了解:https://blog.csdn.net/sunao2002002/article/details/50611838https...

首先,要学习一下大佬关于鸿蒙M核动态内存的系列博客:https://bbs.huaweicloud.com/blogs/279703

自己结合代码,理解一下底层的基本原理。

一、关于TLSF算法

TLSF是一个动态内存的分配算法,通过以下两篇文章可以对此有一个大概的了解:

https://blog.csdn.net/sunao2002002/article/details/50611838

https://www.codenong.com/cs106845116/

TLSF算法中,将一整块动态内存池,划分为了许多个小内存块。比如在鸿蒙M核里,所有的内存块,都是被放在了链表里。TLSF使用了两级索引,即每个内存块,都可以由FL(first level)和SL(second level)两个索引来精确表示。128Byte大小以下的内存块,只需要单独一个FL即可以表示它位于哪个链表;而128Byte以上,2^31Byte以下的“大内存块”,需要由FL和SL两个索引来表示。

TLSF算法中,给出了计算两个索引的公式(背后的原理,要仔细学习一下上面两篇介绍TLSF的文章)

公式的变体为:

在鸿蒙M核中,SLI使用固定值3,即对于大块的内存,比如2^7~2^8区间,被分成了8等份,放在八个链表中。

单独看一下这个公式变体,因为这个比较方便通过位操作来实现:

,后面的代码里会有体现。

二、关于OsMemPoolHead->freeList数组

结合《鸿蒙轻内核M核源码分析系列九 动态内存Dynamic Memory 第一部分》和代码可以知道,freeList是一个数组。那么这个数组有多少个元素呢?或者说有多少个桶呢?小块内存,4 ~ 128Byte,一共有31个桶,对应数组下标0~30;大块内存,2^7 ~ 2^30 Byte,一共有24 * 8 = 192个桶,对应数组下标31 ~ 222。

三、关于kernel/src/mm/los_memory.c里重要的宏和方法

代码里的宏和方法,很重要的是为了解决一个关键问题:freeList一共有223个元素,每个元素都指向一个由内存块组成的链表,我们暂且叫它们为223个桶。那么问题是:给定一个size大小的内存,如果确定它属于哪个桶?即给定一个内存块,大小为size,那么他属于freeList[index]链表,index是几?

小块内存比较简单,这里暂不做讨论。考虑大块内存的场景,index = 小块内存数量(固定为31) + (log2(size)取整 - 7)*8 + SL。

比如size=129,129 = 2^7 + 1,二进制表示为1000 0001。小块内存数量是31,log2(size)取整 = 7,SL=0,计算出来属于freeList[31]。它刚刚好就是第一个大块内存的桶,即第32个桶,index=31。

再大一点比如size=560, 560 = 2^9 + 48,二进制表示为0010 0011 0000,小块内存数量是31,log2(size)取整 = 9,SL=0,计算出来属于freeList[47]。

那么接下来再来看代码中“令人头疼”的宏定义:

1、OsMemFFS、OsMemFLS

这个FFS,Find First S、Find Last S,S是啥我没看出来:(。比如十进制240,以UINT32表示是 00000000 00000000 00000000 11110000,

OsMemFFS(240):

OS_MEM_BITMAP_MASK=31,

~bitmap = 11111111 11111111 11111111 00001111,

~bitmap+1 = 11111111 11111111 11111111 00010000,

bitmap &= ~bitmap + 1后,bitmap=00000000 00000000 00000000 00010000,

CLZ(bitmap) = 27,

OS_MEM_BITMAP_MASK-CLZ(bitmap) = 4;

OsMemFLS(240):

CLZ(bitmap) = 24,

OS_MEM_BITMAP_MASK-CLZ(bitmap) = 7

理解一下:OsMemFLS,就是求出了一个十进制数,拿二进制表示时,最高的1bit是第几位。关键点来了,它的数学意义就是,log2(size)取整。log2(240) 取整等于7。

所有OsMemFLS单词里面的last bit,就是从低位开始,即从右向左数,第0位开始,最后一个bit位是第几位。

2、OsMemLog2,

有了对FLS的理解,这里就好理解了。给定一个size,求log2(size)的整数部分。

3、STATIC INLINE UINT32 OsMemFlGet(UINT32 size)

第一个if,处理小块内存,size小于128的场景,直接将size/4-1,得到其所属桶的index。

重点看return部分。TLSF算法里,标准的FL,就是等于log2(size);但是代码里将它减去了一个OS_MEM_LARGE_START_BUCKET(=7),再加上OS_MEM_SMALL_BUCKET_COUNT(=31)。经过一减一加,其实已经失去了数学上的含义。

4、STATIC INLINE UINT32 OsMemSlGet(UINT32 size, UINT32 fl)

我们拿红箭头所指的公式,转换成位操作:SL = (size << SLI >> FL)-(1 << SLI)

再看代码,终于能看懂这左移右移的神操作了。

5、最后,我们最终目的是通过size,计算freeList[index] 中的index。

STATIC INLINE UINT32 OsMemFreeListIndexGet(UINT32 size)

经过前面对FL,SL的理解,我们先自己尝试推导index的计算公式:index = 小块内存数量(固定为31) + (log2(size)取整 - 7)*8 + SL

这里有两种FL。一种是数学上的,129的FL = 7;另外一种是代码里的,129的fl = 7-7+31 = 31。

再仔细看下代码,(fl - OS_MEM_SMALL_BUCKET_COUNT) 就是(log2(size)取整 - 7,<<OS_MEM_SLI就是<<3,就是乘以8!剩下的就是加减法了。

四、总结

对于本篇文章介绍的宏和函数,首先要理解。

更重要的是要记住,给定内存块大小为size,通过 OsMemFreeListIndexGet(size),即可得到其所属的桶的index,即freeList[index]。

比如拆分内存,拆出来的内存应该放到哪个链表?申请内存,应该从哪个链表申请?回收内存,应该放到哪个链表里?这些都是用到了OsMemFreeListIndexGet(size)函数。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。