add jump inside page under mm.md

This commit is contained in:
Yan_yan 2020-11-12 15:40:47 +08:00
parent a84a346821
commit 4c79e590c1
2 changed files with 55 additions and 15 deletions

View File

@ -1,46 +1,77 @@
# 内存管理
* [前言](#intro)
* [内存堆](#mm_heap)
* [静态内存管理](#mm_heap_static)
* [静态内存划分](#mm_heap_static_split)
* [静态内存分配](#mm_heap_static_alloc)
* [静态内存释放](#mm_heap_static_free)
* [动态内存管理](#mm_heap_dynamic)
* [动态内存划分](#mm_heap_dynamic_split)
* [动态内存分配](#mm_heap_dynamic_alloc)
* [动态内存释放](#mm_heap_dynamic_free)
* [内存池](#mempool)
* [函数接口](#func_api)
* [应用场景](#situation)
<span id="intro"></span>
## 前言
XiUOS操作系统提供了独特的内存管理分配算法进行内存管理通过静态内存管理和动态内存管理相结合保证分配和释放内存的实时性提高内存的使用率有效地规避了内存碎片问题同时增加了内存检索的速度。
</br></br>
<span id="mm_heap"></span>
## 内存堆
<span id="mm_heap_static"></span>
### 静态内存管理
<span id="mm_heap_static_split"></span>
#### 静态内存划分
静态内存包含2个链表。其中每个链表都具有block_size静态内存块大小、total_count静态内存块的总个数、free_count空闲内存块的总个数和free_list空闲链表这四个属性。
其中block_size属性记录了当前链表中每个静态内存块的大小
total_count属性记录了系统初始化之后分配给该链表中静态内存块的总个数
free_count属性记录了该链表中还可以分配给用户静态内存块的个数
free_list属性则真正指向各个空闲静态内存块。
</br></br>
下图为静态内存链表的具体情况。图中包括两个静态链表1和2。静态链表头1指向的内存池中存放的静态内存块的大小都是32字节静态链表头2所指向的内存池中存放的静态内存块的大小都是64字节。此外系统分别配置了静态链表头1和静态链表头2中静态内存块的total_count个数为256和128。因此静态链表头1最多可以响应用户256次的小于32字节的内存请求静态链表头2最多可以响应用户128次的介于33-64字节之间的内存请求一旦对应的静态内存块分配完了系统会向动态内存区域寻求内存空间分配。
* block_size 记录了当前链表中每个静态内存块的大小
* total_count 记录了系统初始化之后分配给该链表中静态内存块的总个数
* free_count 记录了该链表中还可以分配给用户静态内存块的个数
* free_list 则真正指向各个空闲静态内存块
下图为静态内存链表的具体情况图中包括两个静态链表1和2。静态链表头1指向的内存池中存放的静态内存块的大小都是32字节静态链表头2所指向的内存池中存放的静态内存块的大小都是64字节。此外系统分别配置了静态链表头1和静态链表头2中静态内存块的total_count个数为256和128。因此静态链表头1最多可以响应用户256次的小于32字节的内存请求静态链表头2最多可以响应用户128次的介于33-64字节之间的内存请求一旦对应的静态内存块分配完了系统会向动态内存区域寻求内存空间分配。
<div style="display: flex;justify-content: center;align-items: center;">
<img src="./imagesrc/fig1.png" width =100%/>
</div>
<span id="mm_heap_static_alloc"></span>
#### 静态内存分配
在用户发起内存分配请求时,若用户请求分配的内存空间大小小于等于预设的静态内存阈值,且所述静态内存区域有相应空闲的内存块,则从静态内存区域分配相应大小的内存空间。
</br></br>
在用户发起内存释放请求时,所述分配释放请求解析根据用户提供的内存地址决定后续的操作:
</br>
如果所述内存地址是不合法的,则直接返回结果给用户。
</br>
如果所述内存地址是合法地址,分配释放请求解析模块解析所述内存地址所属内存区域,所述内存地址在静态内存区域,则内存分配任务由静态内存管理模块负责;所述内存地址在动态内存区域,则内存分配任务由动态内存管理模块负责。
</br></br>
> 如果所述内存地址是不合法的,则直接返回结果给用户。
> 如果所述内存地址是合法地址,分配释放请求解析模块解析所述内存地址所属内存区域,所述内存地址在静态内存区域,则内存分配任务由静态内存管理模块负责;所述内存地址在动态内存区域,则内存分配任务由动态内存管理模块负责。
从静态内存区域分配静态内存块的过程,包括三种情况。</br>
+ 当用户请求分配内存大小小于等于32字节那么分配释放请求解析模块解析该内存大小由静态内存管理模块负责。系统获取静态链表头1从静态链表头1中获取一个静态内存块返回给用户</br>
+ 当用户请求分配内存大小为3364字节那么分配释放请求解析模块解析该内存大小由静态内存管理模块负责。系统获取静态链表头2从静态链表头2中获取一个静态内存块返回给用户</br>
+ 若所获得的静态链表头是一个空的链表,即没有空闲的静态内存块可用,那么通知分配释放请求解析模块在静态内存区域中内存分配失败。
<span id="mm_heap_static_free"></span>
#### 静态内存释放
当用户请求释放内存所述内存用ptr表示释放操作包括三种情况。</br>
+ 所述ptr内存地址是不合法的则直接返回释放操作。</br>
+ 所述ptr指向的静态内存块属于静态链表头1管理则将所述ptr指向的静态内存块放置到链表头1的头部</br>
+ 若所述ptr指向的静态内存块属于链表头2管理则将所述ptr指向的静态内存块放置到链表头2的头部。
<span id="mm_heap_dynamic"></span>
### 动态内存管理
<span id="mm_heap_dynamic_split"></span>
#### 动态内存划分
静态内存划分后剩下的内存区域作为动态内存分配给动态内存区域。动态内存区域管理用到了三种重要的数据结构分别是已分配动态内存段、空闲动态内存段和动态内存管理数据结构。下图显示了已分配动态内存段和空闲动态内存段这两种数据结构。其中已分配动态内存包括元数据信息和用户的数据段用户数据元数据信息中的size属性记录了该动态内存段的内存大小prev_size属性则记录了该动态内存段前一个相邻动态内存段的内存大小从而可以获取前一个相邻动态内存段。用户数据则是分配给用户使用的内存空间。空闲动态内存段的元数据信息具有size、prev_size、prev和next这四个属性其中size和prev_size属性与已分配动态内存段的对应属性表示的意义相同prev属性记录了前一个空闲动态内存段最后一个next属性则记录了下一个空闲动态内存段。
</br></br>
@ -110,6 +141,7 @@ free_list属性则真正指向各个空闲静态内存块。
</table>
</div>
<span id="mm_heap_dynamic_alloc"></span>
#### 动态内存分配
系统根据要分配或者要释放的内存段大小计算要操作的内存段链表头当内存段大小为1 ~ 31字节那么内存计算单元计算之后将获取空闲动态链表头freeList1当内存段大小为32 ~63字节那么内存计算单元计算之后将获取动态链表头freeList2。以此类推。</br></br>
@ -119,6 +151,8 @@ free_list属性则真正指向各个空闲静态内存块。
+ 用户请求分配8000个字节。内存计算单元计算8000字节对应的空闲动态链表获取freeList9freeList9链表中没有空闲动态内存段没有找到可分配的动态内存段并且freeList9不是最后一级链表更新链表头到freeList10freeList10链表中动态内存段可以满足用户的需求之后进行内存块的分割操作9000可以分配为8192字节 + 808字节808字节大于系统要求的8字节对齐大小因此除了返回8192动态内存给用户还要执行808字节的释放操作</br>
+ 用户请求分配6000000个字节。内存计算单元计算6000000字节对应的空闲动态链表获取freeList10freeList10链表中没有空闲动态内存段没有找到可分配的动态内存段并且freeList10是最后一级链表内存分配操作失败结束内存分配操作。</br>
<span id="mm_heap_dynamic_free"></span>
#### 动态内存释放
当用户请求释放内存所述内存用ptr表示。分配释放请求解析模块解析判断ptr所述区域为动态内存区域则将释放ptr所指向的内存区域到动态内存段中。
@ -130,12 +164,16 @@ free_list属性则真正指向各个空闲静态内存块。
+ 如图中a所示四块动态内存段其中ABD三段为已分配动态内存段C为空闲动态内存段。当前系统要释放内存段B动态内存管理模块检测到B内存段的后一个相邻C也是空闲内存段则系统会合并内存段BC然后释放BC合并之后的内存段。
+ 如图中b所示ABCD四块已分配内存段。系统要释放内存段B动态内存管理模块检测到B的相邻内存段都是已分配内存段那么直接释放内存段B。
+ 如图中c所示四块动态内存段其中AC是空闲内存段BD是已分配内存段。系统要释放内存段B动态内存管理模块检测到B的前一个相邻内存段A和后一个相邻内存段B都是空闲内存段那么先合并ABC三个内存段形成一个大的空闲内存段ABC然后释放合并形成的ABC空闲内存段。
<span id="mempool"></span>
## 内存池
内存堆管理器可以分配任意大小的内存块非常灵活和方便。但其也存在明显的缺点一是分配效率不高在每次分配时都要空闲内存块查找二是容易产生内存碎片。为了提高内存分配的效率并且避免内存碎片XiUOS提供了另外一种内存管理方法内存池。
</br></br>
内存池在创建时先向系统预先申请分配一定数量、大小相等(一般情况下)的内存块留作备用。当有新的内存需求时,就从内存池中分出一部分内存块,若内存块不够再继续申请新的内存。
<span id="func_api"></span>
## 函数接口
### 内存堆管理
@ -354,6 +392,8 @@ void xs_GmSetFreeHook(void (*gm_release_hook)(struct xs_MemGather *gm, void *dat
| gm_release_hook | 钩子函数指针 |
</br>
<span id="situation"></span>
## 应用场景
### 内存堆应用场景
+ 为数组动态分配内存的常规场景。

View File

@ -10,7 +10,7 @@
* [信号量](#sem)
* [互斥量](#mutex)
* [事件集](#event)
* [任务切换时间测试](#time_test)
* [时间测试](#time_test)
* [概述](#time_test_intro)
* [基于 ARM 处理器的任务切换时间测试](#time_test_arm)
* [基于 RISC-V 处理器的任务切换时间测试](#time_test_riscv)
@ -541,7 +541,7 @@ xs_int32 xs_UserEventReinit(xs_uint16 id);
<span id="time_test"></span>
## 任务切换时间测试
## 时间测试
<span id="time_test_intro"></span>