add jump inside page under mm.md
This commit is contained in:
parent
a84a346821
commit
4c79e590c1
|
@ -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操作系统提供了独特的内存管理分配算法进行内存管理,通过静态内存管理和动态内存管理相结合,保证分配和释放内存的实时性,提高内存的使用率,有效地规避了内存碎片问题,同时增加了内存检索的速度。
|
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空闲链表这四个属性。
|
静态内存包含2个链表。其中,每个链表都具有block_size静态内存块大小、total_count静态内存块的总个数、free_count空闲内存块的总个数和free_list空闲链表这四个属性。
|
||||||
其中block_size属性记录了当前链表中每个静态内存块的大小,
|
* block_size 记录了当前链表中每个静态内存块的大小
|
||||||
total_count属性记录了系统初始化之后分配给该链表中静态内存块的总个数,
|
* total_count 记录了系统初始化之后分配给该链表中静态内存块的总个数
|
||||||
free_count属性记录了该链表中还可以分配给用户静态内存块的个数,
|
* free_count 记录了该链表中还可以分配给用户静态内存块的个数
|
||||||
free_list属性则真正指向各个空闲静态内存块。
|
* free_list 则真正指向各个空闲静态内存块
|
||||||
</br></br>
|
|
||||||
下图为静态内存链表的具体情况。图中包括两个静态链表1和2。静态链表头1指向的内存池中存放的静态内存块的大小都是32字节,静态链表头2所指向的内存池中存放的静态内存块的大小都是64字节。此外,系统分别配置了静态链表头1和静态链表头2中静态内存块的total_count个数为256和128。因此,静态链表头1最多可以响应用户256次的小于32字节的内存请求,静态链表头2最多可以响应用户128次的介于33-64字节之间的内存请求,一旦对应的静态内存块分配完了,系统会向动态内存区域寻求内存空间分配。
|
下图为静态内存链表的具体情况,图中包括两个静态链表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;">
|
<div style="display: flex;justify-content: center;align-items: center;">
|
||||||
<img src="./imagesrc/fig1.png" width =100%/>
|
<img src="./imagesrc/fig1.png" width =100%/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<span id="mm_heap_static_alloc"></span>
|
||||||
|
|
||||||
#### 静态内存分配
|
#### 静态内存分配
|
||||||
在用户发起内存分配请求时,若用户请求分配的内存空间大小小于等于预设的静态内存阈值,且所述静态内存区域有相应空闲的内存块,则从静态内存区域分配相应大小的内存空间。
|
在用户发起内存分配请求时,若用户请求分配的内存空间大小小于等于预设的静态内存阈值,且所述静态内存区域有相应空闲的内存块,则从静态内存区域分配相应大小的内存空间。
|
||||||
</br></br>
|
</br></br>
|
||||||
在用户发起内存释放请求时,所述分配释放请求解析根据用户提供的内存地址决定后续的操作:
|
在用户发起内存释放请求时,所述分配释放请求解析根据用户提供的内存地址决定后续的操作:
|
||||||
</br>
|
|
||||||
如果所述内存地址是不合法的,则直接返回结果给用户。
|
> 如果所述内存地址是不合法的,则直接返回结果给用户。
|
||||||
</br>
|
> 如果所述内存地址是合法地址,分配释放请求解析模块解析所述内存地址所属内存区域,所述内存地址在静态内存区域,则内存分配任务由静态内存管理模块负责;所述内存地址在动态内存区域,则内存分配任务由动态内存管理模块负责。
|
||||||
如果所述内存地址是合法地址,分配释放请求解析模块解析所述内存地址所属内存区域,所述内存地址在静态内存区域,则内存分配任务由静态内存管理模块负责;所述内存地址在动态内存区域,则内存分配任务由动态内存管理模块负责。
|
|
||||||
</br></br>
|
|
||||||
|
|
||||||
从静态内存区域分配静态内存块的过程,包括三种情况。</br>
|
从静态内存区域分配静态内存块的过程,包括三种情况。</br>
|
||||||
+ 当用户请求分配内存大小小于等于32字节,那么分配释放请求解析模块解析该内存大小由静态内存管理模块负责。系统获取静态链表头1,从静态链表头1中获取一个静态内存块返回给用户;</br>
|
+ 当用户请求分配内存大小小于等于32字节,那么分配释放请求解析模块解析该内存大小由静态内存管理模块负责。系统获取静态链表头1,从静态链表头1中获取一个静态内存块返回给用户;</br>
|
||||||
+ 当用户请求分配内存大小为33~64字节,那么分配释放请求解析模块解析该内存大小由静态内存管理模块负责。系统获取静态链表头2,从静态链表头2中获取一个静态内存块返回给用户;</br>
|
+ 当用户请求分配内存大小为33~64字节,那么分配释放请求解析模块解析该内存大小由静态内存管理模块负责。系统获取静态链表头2,从静态链表头2中获取一个静态内存块返回给用户;</br>
|
||||||
+ 若所获得的静态链表头是一个空的链表,即没有空闲的静态内存块可用,那么通知分配释放请求解析模块在静态内存区域中内存分配失败。
|
+ 若所获得的静态链表头是一个空的链表,即没有空闲的静态内存块可用,那么通知分配释放请求解析模块在静态内存区域中内存分配失败。
|
||||||
|
|
||||||
|
<span id="mm_heap_static_free"></span>
|
||||||
|
|
||||||
#### 静态内存释放
|
#### 静态内存释放
|
||||||
当用户请求释放内存,所述内存用ptr表示,释放操作包括三种情况。</br>
|
当用户请求释放内存,所述内存用ptr表示,释放操作包括三种情况。</br>
|
||||||
+ 所述ptr内存地址是不合法的,则直接返回释放操作。</br>
|
+ 所述ptr内存地址是不合法的,则直接返回释放操作。</br>
|
||||||
+ 所述ptr指向的静态内存块属于静态链表头1管理,则将所述ptr指向的静态内存块放置到链表头1的头部;</br>
|
+ 所述ptr指向的静态内存块属于静态链表头1管理,则将所述ptr指向的静态内存块放置到链表头1的头部;</br>
|
||||||
+ 若所述ptr指向的静态内存块属于链表头2管理,则将所述ptr指向的静态内存块放置到链表头2的头部。
|
+ 若所述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属性则记录了下一个空闲动态内存段。
|
静态内存划分后,剩下的内存区域作为动态内存分配给动态内存区域。动态内存区域管理用到了三种重要的数据结构,分别是已分配动态内存段、空闲动态内存段和动态内存管理数据结构。下图显示了已分配动态内存段和空闲动态内存段这两种数据结构。其中,已分配动态内存包括元数据信息和用户的数据段(用户数据),元数据信息中的size属性记录了该动态内存段的内存大小,prev_size属性则记录了该动态内存段前一个相邻动态内存段的内存大小,从而可以获取前一个相邻动态内存段。用户数据则是分配给用户使用的内存空间。空闲动态内存段的元数据信息具有size、prev_size、prev和next这四个属性,其中,size和prev_size属性与已分配动态内存段的对应属性表示的意义相同,prev属性记录了前一个空闲动态内存段,最后一个next属性则记录了下一个空闲动态内存段。
|
||||||
</br></br>
|
</br></br>
|
||||||
|
@ -110,6 +141,7 @@ free_list属性则真正指向各个空闲静态内存块。
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<span id="mm_heap_dynamic_alloc"></span>
|
||||||
|
|
||||||
#### 动态内存分配
|
#### 动态内存分配
|
||||||
系统根据要分配或者要释放的内存段大小计算要操作的内存段链表头,当内存段大小为1 ~ 31字节,那么内存计算单元计算之后将获取空闲动态链表头freeList1,当内存段大小为32 ~63字节,那么内存计算单元计算之后将获取动态链表头freeList2。以此类推。</br></br>
|
系统根据要分配或者要释放的内存段大小计算要操作的内存段链表头,当内存段大小为1 ~ 31字节,那么内存计算单元计算之后将获取空闲动态链表头freeList1,当内存段大小为32 ~63字节,那么内存计算单元计算之后将获取动态链表头freeList2。以此类推。</br></br>
|
||||||
|
@ -119,6 +151,8 @@ free_list属性则真正指向各个空闲静态内存块。
|
||||||
+ 用户请求分配8000个字节。内存计算单元计算8000字节对应的空闲动态链表,获取freeList9,freeList9链表中没有空闲动态内存段,没有找到可分配的动态内存段并且freeList9不是最后一级链表,更新链表头到freeList10,freeList10链表中动态内存段可以满足用户的需求,之后进行内存块的分割操作,9000可以分配为8192字节 + 808字节,808字节大于系统要求的8字节对齐大小,因此,除了返回8192动态内存给用户,还要执行808字节的释放操作;</br>
|
+ 用户请求分配8000个字节。内存计算单元计算8000字节对应的空闲动态链表,获取freeList9,freeList9链表中没有空闲动态内存段,没有找到可分配的动态内存段并且freeList9不是最后一级链表,更新链表头到freeList10,freeList10链表中动态内存段可以满足用户的需求,之后进行内存块的分割操作,9000可以分配为8192字节 + 808字节,808字节大于系统要求的8字节对齐大小,因此,除了返回8192动态内存给用户,还要执行808字节的释放操作;</br>
|
||||||
+ 用户请求分配6000000个字节。内存计算单元计算6000000字节对应的空闲动态链表,获取freeList10,freeList10链表中没有空闲动态内存段,没有找到可分配的动态内存段并且freeList10是最后一级链表,内存分配操作失败,结束内存分配操作。</br>
|
+ 用户请求分配6000000个字节。内存计算单元计算6000000字节对应的空闲动态链表,获取freeList10,freeList10链表中没有空闲动态内存段,没有找到可分配的动态内存段并且freeList10是最后一级链表,内存分配操作失败,结束内存分配操作。</br>
|
||||||
|
|
||||||
|
<span id="mm_heap_dynamic_free"></span>
|
||||||
|
|
||||||
#### 动态内存释放
|
#### 动态内存释放
|
||||||
当用户请求释放内存,所述内存用ptr表示。分配释放请求解析模块解析判断ptr所述区域为动态内存区域,则将释放ptr所指向的内存区域到动态内存段中。
|
当用户请求释放内存,所述内存用ptr表示。分配释放请求解析模块解析判断ptr所述区域为动态内存区域,则将释放ptr所指向的内存区域到动态内存段中。
|
||||||
|
|
||||||
|
@ -131,11 +165,15 @@ free_list属性则真正指向各个空闲静态内存块。
|
||||||
+ 如图中(b)所示,A,B,C,D四块已分配内存段。系统要释放内存段B,动态内存管理模块检测到B的相邻内存段都是已分配内存段,那么直接释放内存段B。
|
+ 如图中(b)所示,A,B,C,D四块已分配内存段。系统要释放内存段B,动态内存管理模块检测到B的相邻内存段都是已分配内存段,那么直接释放内存段B。
|
||||||
+ 如图中(c)所示,四块动态内存段,其中,A,C是空闲内存段,B,D是已分配内存段。系统要释放内存段B,动态内存管理模块检测到B的前一个相邻内存段A和后一个相邻内存段B都是空闲内存段,那么先合并A,B,C三个内存段形成一个大的空闲内存段ABC,然后释放合并形成的ABC空闲内存段。
|
+ 如图中(c)所示,四块动态内存段,其中,A,C是空闲内存段,B,D是已分配内存段。系统要释放内存段B,动态内存管理模块检测到B的前一个相邻内存段A和后一个相邻内存段B都是空闲内存段,那么先合并A,B,C三个内存段形成一个大的空闲内存段ABC,然后释放合并形成的ABC空闲内存段。
|
||||||
|
|
||||||
|
<span id="mempool"></span>
|
||||||
|
|
||||||
## 内存池
|
## 内存池
|
||||||
内存堆管理器可以分配任意大小的内存块,非常灵活和方便。但其也存在明显的缺点:一是分配效率不高,在每次分配时,都要空闲内存块查找;二是容易产生内存碎片。为了提高内存分配的效率,并且避免内存碎片,XiUOS提供了另外一种内存管理方法:内存池。
|
内存堆管理器可以分配任意大小的内存块,非常灵活和方便。但其也存在明显的缺点:一是分配效率不高,在每次分配时,都要空闲内存块查找;二是容易产生内存碎片。为了提高内存分配的效率,并且避免内存碎片,XiUOS提供了另外一种内存管理方法:内存池。
|
||||||
</br></br>
|
</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 | 钩子函数指针 |
|
| gm_release_hook | 钩子函数指针 |
|
||||||
</br>
|
</br>
|
||||||
|
|
||||||
|
<span id="situation"></span>
|
||||||
|
|
||||||
## 应用场景
|
## 应用场景
|
||||||
### 内存堆应用场景
|
### 内存堆应用场景
|
||||||
+ 为数组动态分配内存的常规场景。
|
+ 为数组动态分配内存的常规场景。
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
* [信号量](#sem)
|
* [信号量](#sem)
|
||||||
* [互斥量](#mutex)
|
* [互斥量](#mutex)
|
||||||
* [事件集](#event)
|
* [事件集](#event)
|
||||||
* [任务切换时间测试](#time_test)
|
* [时间测试](#time_test)
|
||||||
* [概述](#time_test_intro)
|
* [概述](#time_test_intro)
|
||||||
* [基于 ARM 处理器的任务切换时间测试](#time_test_arm)
|
* [基于 ARM 处理器的任务切换时间测试](#time_test_arm)
|
||||||
* [基于 RISC-V 处理器的任务切换时间测试](#time_test_riscv)
|
* [基于 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"></span>
|
||||||
|
|
||||||
## 任务切换时间测试
|
## 时间测试
|
||||||
|
|
||||||
<span id="time_test_intro"></span>
|
<span id="time_test_intro"></span>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue