改进LiteOS中物理内存分配算法

news2024/10/6 4:01:35

一、实验要求

优化TLSF算法,将Best-fit策略优化为Good-fit策略,进一步降低时间复杂度至O(1)。

优化思路:

1.初始化时预先为每个桶挂上若干空闲块,在实际分配时避免分割(split)操作,加速分配过程;

2.定位到比当前所需空间更大一级的桶进行空闲块分配,避免因遍历链表寻找合适大小的空闲块所导致的时间浪费。

二、实验准备

第1步:下载带有TLSF算法的源码

在这里下载OpenHarmony 1.1.0 LTS,实测内部含有内存两级分割策略算法(TLSF算法)的代码实现,repo地址如下:

repo init -u https://gitee.com/openharmony/manifest.git -b refs/tags/OpenHarmony_release_v1.1.0 --no-repo-verify

原本的想法是要编写一个程序来验证新内存分配算法的正确性,但由于补丁只能打1.0版本,而这个是1.1版本,抱有侥幸心理试试补丁能不能打1.x版本,于是下载了这个版本,事实证明补丁依旧不能打上..

在openharmony/kernel/liteos_a/kernel/base/mem下有一个tlsf文件夹,这个文件夹里存储的正是tlsf算法的实现:

 

进入到tlsf文件夹下的los_memory.c文件中。

第2步:查看结构体

图中的结构体如下:

OsMemPoolInfo

OsMemFreeNodeHead

OsMemNodeHead

OsMemUsedNodeHead

第3步:检查常用宏

宏的含义可参考ppt。

第4步:理解TLSF算法

TLSF算法采用的是两级索引。右边的是第一级索引,将空间按2的指数大小(2^{_{5}}=322^{6}=642^{7}=128...)进行分块。其内部的内存块是否空闲用位图(一维数组)进行标识,1表示块内有剩余空间,0表示块内已经被挤得满满的。

中间的是第二级索引,二级索引在一级索引分块的基础上,进一步进行分块,如图中将一级索引中的每块进一步分成了8块(例如32-63这段被分为了32-35,36-39,40-43,44-47,48-51,52-55,56-59,60-63,每块长度是4)。用位图(二维数组)标识是否存在空闲内存块。有空闲的块标记为1,没有空闲的块标记为0。

左边的是空闲块,空闲块的大小是一个确定的值,该值要在二级索引的区间范围之内。

上图告诉我们鸿蒙系统将内存块大小分为两个部分:4~1272^{7}~2^{31}

在4~127区间上是小桶申请,可以这么理解:在4~127区间上有31个桶(4,8,12,...,124),每个桶的大小代表了所能挂的空闲块的大小(比如12代表只能挂12B大小的空闲块,120代表只能挂120B大小的空闲块),没有二级索引。

大于127的是大桶申请,可以这么理解一共有24个大桶(2^{7}~2^{8}-12^{8}~2^{9}-1,... ,2^{30}~2^{31}-1),这里的大桶代表了一级索引;然后每个大桶里又有8个小桶,这里的小桶代表2级索引;然后每个小桶里又可以挂若干个空闲块。

三、改进TLSF算法

事先说明:

1. 修改不保证完全正确,如有疏漏,望请指正。

2. 所修改的函数都在openharmony/kernel/liteos_a/kernel/base/mem/tlsf下的los_memory.c文件中。

3.所修改的源码是OpenHarmony 1.1.0 LTS版本,其它版本可能会有所差异。

1.定位到比当前所需空间更大一级的桶

修改对象:OsMemFreeListIndexGet函数

修改方法如下:

首先复制OsMemFreeListIndexGet这个函数,粘贴到原函数下面,改名为NewOsMemFreeListIndexGet。

fl的值表示的是在一级索引中的位置,OS_MEM_SMALL_BUCKET_MAX_SIZE是一个宏其值为128,如果size<124,就让fl+1,相当于索引指向当前桶的上一级桶。

如果size>=124此时考虑临界状态,当size为124时上一级桶会进入到大桶的范围(因为小桶的最大上界为127),所以此时会返回newFl。

newFl会进入到OsMemSlGet函数,这个函数大致的作用就是返回某个值在二级索引中的位置(具体解释同样在下一节),所以sl的值代表了size在二级索引中的位置。

此时我们让sl+1,就相当于指向了下一个位置的二级索引,最后这里return的这一长串数很巧妙,同样在下一节解释。

 2.初始化时预先为每个桶挂上若干空闲块

修改对象:OsMemPoolInit函数、OsMemFreeNodeAdd函数

修改方法如下:

这里同样只讲大致思路,具体分析请参考第六节:

OsMemPoolInit这个函数是用于初始化内存池的,可以在该函数中预先挂上空闲块。

首先我定义了一个名为currentNode的OsMemNodeHead结构体指针,指向的是初始节点(newNode)的末尾,即后续空闲的线性空间的开头,用于存储新的结构体和空闲块。

preveNode的作用是要记录前驱节点,方便后续双向链表的构建。

然后我定义了n和sizeArray这里是用于指定想要在哪个桶上挂空闲块(比如12代表想要在大小为12B的桶上挂空闲块),可以根据自己的需要将空闲块挂到其它桶上,只需修改size的值即可。

在for循环里主要就是给freeNode结构体内的参数赋值,freeNode指向的是newNode的末尾地址,即未被占用的线性空间开头的位置。

如果i==0,前驱节点要指向newNode,如果i>0此时preveNode的作用就凸显出来,freeNode(当前节点)的前驱就指向preveNode(前一个节点)。

然后调用NewOsMemFreeNodeAdd函数,这个函数主要是将结构体插入到索引当中。

preveNode = freeNode是令前一个节点指向当前节点。

最后一行是令currentNode指向后续空闲空间的起始位置,方便添加新的结构体。

在OsMemPoolInit函数中调用到NewOsMemFreeNodeAdd这个函数,这个函数原名是OsMemFreeNodeAdd,只需在前面加上New即可,然后这里就和本节1中修改的NewOsMemFreeListIndexGet函数联系在一起。

四、源码解析+修改逻辑分析

1.定位到比当前所需空间更大一级的桶

首先我们分析一下OsMemFlGet这个函数,调用逻辑是:OsMemFlGet->OsMemLog2->OsMemFLS->

我们直接看OsMemFLS函数,OS_MEM_BITMAP_MASK是一个宏定义,代表数31(0到31共计32位,因为操作系统是32位的)。

CLZ是“Count Leading Zeros”的缩写,用于统计二进制数前导0的个数(比如一个32位的数0000010100...,前导0有5个)。

OS_MEM_BITMAP_MASK-CLZ(bitmap)是计算第1个“1”所在的位置(比如上面举例的32位数0000010100...,前导0有5个,用31-5得到的就是该数最高位的“1”所在的位置是26),这个的用处就是去定位这个数是在哪一个一级索引里(比如上面那个数最后会被放在2^26~2^27-1这个一级索引里),参考下面的图来理解:

接下来我们看OsMemSlGet函数,OS_MEM_SLI是一个宏定义值为3,OS_MEM_FREE_LIST_NUM是1<<3,即值为8。

size << OS_MEM_SLI是将size扩大8倍,(size << OS_MEM_SLI)>>fl是将乘8后的size再除以2^fl倍,这个的目的是得到二级索引的值,不至于移除低位导致精度缺失(比如对于数111000000,fl即一级索引是8,如果不乘8,此时将该数右移8位结果为1,明显不对,而乘8后右移8位结果为1110,十进制为14,此时减8,结果为6,表明该数在一级索引中是2^9~2^10-1,在二级索引中排在第6个块中)。

最后解释一下return的这段代码的含义,我首先各处各个变量代表的含义:OS_MEM_SMALL_BUCKET_COUNT=31,代表小桶一共被分为31个区间。OS_MEM_LARGE_START_BUCKET=7,2^7=128即大桶开始的位置。sl返回的是2级索引的值。fl是1级索引的值。

然后我们看表达式:fl - OS_MEM_LARGE_START_BUCKET,表达式的含义是:size所处的一级索引位置减去大桶开始的位置,如下图1:

 

fl - OS_MEM_LARGE_START_BUCKET) << OS_MEM_SLI,是将上图中那部分一级索引的个数乘以8,为什么要乘以8?因为每个一级索引(大桶)对应有8个二级索引块,所以是计算出二级索引块的个数。

OS_MEM_SMALL_BUCKET_COUNT + ((fl - OS_MEM_LARGE_START_BUCKET) << OS_MEM_SLI),意思是在前面二级索引块数的基础上,再加上一级索引块的数量(因为<128的一级索引属于小桶范畴不具备二级索引,如上图2,所以直接加上即可)。

OS_MEM_SMALL_BUCKET_COUNT + ((fl - OS_MEM_LARGE_START_BUCKET) << OS_MEM_SLI) + sl就是把所有的小桶+大桶的二级索引块全部加上,然后加上sl自身这个块的偏移量,就能够定位到要在哪个大桶的二级索引块上加入空闲块。

2.初始化时预先为每个桶挂上若干空闲块

首先看osmempoolinit的函数,主要要关注poolHead,newNode,endNode的结构体,这个大家自己看了。

然后要注意newNode = OS_MEM_FIRST_NODE(pool)和endNode=OS_MEM_END_NODE(pool,size)这两个函数对应的是一段计算公式,计算的是起始地址和结束地址,endNode标记的是末尾结点。

再然后要关注OsMemFreeNodeAdd这个函数,只有理清了这个函数才能真正理解是如何为每个桶挂上空闲块的。

1.分析OsMemPoolHead和OsMemNodeHead结构体

poolHead -> OsMemPoolHead

newNode、endNode -> OsMemNodeHead

OsMemPoolHead包含了OsMemPoolInfo结构体,其中freeList表示索引列表:

OS_MEM_FREE_LIST_COUNT=小桶(31个)+ 大桶(24个)x 8 = 223个

从这里可以看出对于小桶<128,是给每个一级索引分配一个链表,对于大桶,是给每个二级索引分配一个链表,链表可以在后续挂载空闲块。

OsMemFreeNodeHead包含了OsMemNodeHead结构体:

2.OS_MEM_FIRST_NODE(pool)和OS_MEM_END_NODE(pool,size)

3.OsMemFreeNodeAdd函数

补充内存池知识点:

OsMemPoolInit函数用来初始化一个内存池。

内存池(Memory Pool)是一个用于管理内存分配的系统,它预先分配一块大的内存区域,并将其划分为小块以供程序使用。这样做的好处包括减少内存碎片、提高内存分配效率和简化内存管理。

一二级索存在于内存池中,是内存池中的数据结构,它们用于快速定位和管理内存块。

在一个系统中会有多个内存池(比如用户空间和内核空间的内存池)。操作系统的内存不仅由内存池构成还包括页表、段表等,内存池只适用特定场景。空闲块是由内存池中的索引结构组织。

存在问题:1.修改思路。2.一般情况要定位高一级,特殊情况如预先插入桶要正常。3.endNode的size传入有误。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1271191.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

免费使用GPT的网站

登录ChatGPT系统 登录ChatGPT系统 登录ChatGPT系统

使用VScode通过内网穿透在公网环境下远程连接进行开发

文章目录 前言1、安装OpenSSH2、vscode配置ssh3. 局域网测试连接远程服务器4. 公网远程连接4.1 ubuntu安装cpolar内网穿透4.2 创建隧道映射4.3 测试公网远程连接 5. 配置固定TCP端口地址5.1 保留一个固定TCP端口地址5.2 配置固定TCP端口地址5.3 测试固定公网地址远程 前言 远程…

基础课15——语音合成

TTS是语音合成技术的简称&#xff0c;也称为文语转换或语音到文本。它是指将文本转换为语音信号&#xff0c;并通过语音合成器生成可听的语音。TTS技术可以用于多种应用&#xff0c;例如智能语音助手、语音邮件、语音新闻、有声读物等。 TTS技术通常包括以下步骤&#xff1a; …

ubuntu终端代理配置

ubuntu浏览器的无需手动设置,主要解决在终端中的配置问题,按照下面配置后可能会ping不通一些ip,但wget/git都是可以的,具体原因以后再分析 查找端口 首先要找到自己代理对应的HTTP端口,以QV2ray软件作为示例,我为8889 手动配置 # 配置系统proxy export http_proxy=1…

【腾讯云 HAI域探秘】使用高性能应用服务HAI快速开发一款赛博朋克风拼图游戏,化繁从简,低成本进入人工智能时代。

前言 人工智能&#xff08;AI&#xff09;是当今科技领域的热门话题&#xff0c;尤其是自然语言处理&#xff08;NLP&#xff09;技术&#xff0c;它可以让机器理解和生成自然语言。随着大型语言模型&#xff08;LLM&#xff09;的发展&#xff0c;如 GPT-3、DALL-E 等&#xf…

基于SSM医院住院管理系统

摘 要 随着时代的发展&#xff0c;医疗设备愈来愈完善&#xff0c;医院也变成人们生活中必不可少的场所。如今&#xff0c;已经2021年了&#xff0c;虽然医院的数量和设备愈加完善&#xff0c;但是老龄人口也越来越多。在如此大的人口压力下&#xff0c;医院住院就变成了一个问…

引领Serverless构建之路,亚马逊云科技re:Invent 2023首日主题演讲重磅发布

在每年的亚马逊云科技re:lnvent大会&#xff0c;由Peter DeSantis带来的《周一晚间直播》是re:lnvent大会的第一个并让人值得期待的主题演讲。作为亚马逊云科技高级副总裁&#xff0c;Peter发布了数据库和应用领域的三项Serverless创新&#xff0c;使客户能够更快、更轻松地扩展…

RT_Thread_msh_系统msh命令、使用msh时过滤ulog日志、添加msh命令(不带/带参)

1、msh配置 msh功能是自动开启的&#xff0c;配置如下&#xff0c;可以在“RT-Thread Settings”里去修改。 调试过程中遇到msh不能使用&#xff0c;理解msh也是一个线程&#xff0c;有自己的优先级20&#xff0c;高优先级的线程&#xff08;比如main是10&#xff09;如果一直…

自定义 element DatePicker组件指令 使选择器呈现为只读状态,用户无法直接编辑,但可以查看和选择日期

1.问题 现实中遇到列表的搜索条件使用DatePicker 组件进行开始结束时间筛选&#xff0c;但是手动修改input中的值&#xff0c;导致请求参数异常。比如讲clearable设置为false之后还是能手动清空输入框中的值。虽然组件提供了readonly 属性&#xff0c;但是也会让日期选择也无法…

java学习part22包装类

119-面向对象(高级)-包装类的理解_基本数据类型与包装类间的转换_哔哩哔哩_bilibili 1.包装类 2.基本转包装方式 2.1new方式 源码 2.2valueof&#xff08;&#xff09; 3.包装转基本 4.基本类型和包装类型的默认值不一样 比如boolean默认false Boolean默认null&#xff08;对…

电子学会 2023年9月 青少年软件编程Python编程等级考试二级真题解析(选择题+判断题+编程题)

青少年编程Python编程等级考试二级真题解析(选择题+判断题+编程题) 2023年9月 一、选择题(共25题,共50分) 以下代码运行结果是?( ) A. 宸宸 B. 杭杭 C. 玉玉 D. 州州 答案选:A 考点分析:考察python 列表操作 jxw=yyh[2][0],jxw的值是“拱宸桥”,jxw[1]的值是“宸”…

QT QGraphicsItem 图元覆盖导致鼠标点击事件不能传递到被覆盖图元

一、概述 在日常开发中&#xff0c;遇到这样一个问题&#xff0c;线图元和引脚图元重叠&#xff0c;导致点击引脚图元&#xff0c;没有进入引脚图元的鼠标点击事件中。 二、产生原因 如果您的 QGraphicsItem 上有一个图元覆盖了它&#xff0c;可能会导致鼠标事件无法正常触发…

软件设计之原型模式

原型模式是从一个对象再创建另一个可定制的对象&#xff0c;而且不需要知道任何创建的细节。拷贝分浅拷贝和深拷贝。浅拷贝无法拷贝引用对象。在面试的时候&#xff0c;我们会投多家公司&#xff0c;根据岗位的不同我们会适当调整。使用原型模式可以快速达到需求&#xff0c;下…

抖音直播招聘报白如何提高求职者体验?

为了提升抖音直播招聘报白中求职者的体验&#xff0c;以下是一些建议&#xff1a; 提供清晰的招聘流程和信息。在直播招聘开始之前&#xff0c;企业或人力资源公司应提供清晰的流程和信息&#xff0c;包括直播时间和直播平台&#xff0c; 职位信息&#xff0c;招聘要求等&…

ubuntu系统安装及常用软件安装

Ubuntu 22.04 安装及常用软件安装 在日常开发中&#xff0c;习惯了 ubuntu 系统上安装开发工具及一些指令执行的效率较高&#xff0c;且一些编译环境在 windows 下不是很友好&#xff0c;又因为经常折腾会将 ubuntu 系统的文件系统搞坏而需要重新安装&#xff0c;因此本文整理…

智能监控平台/视频共享融合系统EasyCVR接入RTSP协议视频流无法播放原因是什么?

视频集中存储/云存储/视频监控管理平台EasyCVR能在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、整合、集中管理&#xff0c;实现视频资源的鉴权管理、按需调阅、全网分发、智能分析等。AI智能/大数据视频分析EasyCVR平台已经广泛应用在工地、工厂、园区、楼…

25. 深度学习进阶 - 权重初始化,梯度消失和梯度爆炸

文章目录 权重初始化梯度消失与梯度爆炸 Hi&#xff0c;你好。我是茶桁。 咱们这节课会讲到权重初始化、梯度消失和梯度爆炸。咱们先来看看权重初始化的内容。 权重初始化 机器学习在我们使用的过程中的初始值非常的重要。就比如最简单的wxb&#xff0c;现在要拟合成一个yha…

进阶C语言-字符函数和字符串函数

字符函数和字符串函数 &#x1f388;1.函数介绍&#x1f50e;1.1strlen函数&#x1f52d;1.1.1strlen函数的模拟实现&#x1f4d6;1.计数器法&#x1f4d6;2.递归法&#x1f4d6;3.指针-指针 &#x1f50e;1.2strcpy函数&#x1f52d;1.2.1strcpy函数的模拟实现 &#x1f50e;1…

npm上传发布自定义组件超详细流程

前言 vue3&#xff0c;vite&#xff0c;基于element Plus 的el-table二次封装表格并且上传到npm上&#xff0c;让别人可以通过npm安装你的插件。 一、创建一个新的vue 项目 npm create vuelatest 自己取一个名字&#xff0c;然后一直回车 完成以后进入项目npm i,有用到eleme…

VMware虚拟机安装和使用教程(附最新安装包+以ubuntu为例子讲解)

目录 一、VMware Workstation 17 Pro 简介 二、新功能与改进 三、安装教程 3.1、下载安装包 3.2、运行安装包 四、创建虚拟机 五、启动虚拟机 六、总结与展望 一、VMware Workstation 17 Pro 简介 VMware Workstation 17 Pro是VMware公司为专业用户打造的一款虚拟化软件…