07 内存(中)实现内存页面初始化
Posted xuan01
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了07 内存(中)实现内存页面初始化相关的知识,希望对你有一定的参考价值。
初始化:
hal层的初始化函数 init_halmm 中,调用init_memmgr Cosmos物理内存管理器初始化函数,该函数完成对 内存页 结构msadsc_t ,memarea_t 结构的初始化;
内存页结构初始化:
即初始化 msadsc_t 结构对应的变量;init_msadsc_core函数实现: 扫描 phymmarge_t 结构体数组中的信息,只要类型是可用内存,就建立一个masadsc_t 结构体,并把其中的开始地址作为第一个页面地址,接着加上0x1000,循环建立,知道结束地址;然后开始下一个phymmarge_t 结构体;该函数被 init_msadsc 函数调用;
内存区结构初始化:
建立三个memarea_t 结构体变量;
bafhlst_t_init 初始化 bafhlst_t 结构体基本数据; memdivmer_t_init 初始化medivmer_t 结构体的基本数据,并且循环初始化 memdivmer_t 中的dm_mdmlielst数组中的每个bafhlst_t 结构体;;
memarea_t_init 函数初始化 memarea_t 结构体的基本数据,且初始化memarea_t 结构体中的memdivmer_t 结构体;
init_memarea_core函数 :先检查内存空间能否放下memarea_max个memarea_t结构体变量;循环初始化每个memarea_t 结构体变量;并且写入kmachbsp结构中,计算下一个空闲内存的开始地址;
处理初始化内存占用问题:
目前为止,Cosmos内核本身的执行文件,字体文件,有MMU页表,打包的内核映像文件、内存页和内存区的数据结构 ,这些都要占用实际的物理内存, 但是内存页结构 msadsc_t 都是空闲状态;
这样的情况下,会发生一种情况:对调用内存分配的接口进行内存分配,它按既定的分配算法查找空闲的 msadsc_t 结构,一定会找到内核占用的内存页所对应的msadsc_t结构体,并把这个内存页分配出去,并对这个页面进行改写,这样内核数据就会被覆盖,然而这是决不允许的;
所以我们要把这些已经占用的内存页面所对应的 msadsc_t 结构体标记为已分配;
search_krloccupymsadsc_core 函数 :搜索BIOS中断表所占用的内存页对应的 msadsc_t 结构 、内核栈占用的内存页、内核占用的内存页所对应的、内核映像文件占用内存页所对应的结构;
search_segment_occupymsadsc 函数 :搜索出一段内存地址空间对应的 msadsc_t 结构,设置为已分配;
初始化阶段的各种数据占用的开始、结束地址和大小,这些信息都保存在 machbstart_t 结构体中,以它为参数;
其实,phymmarge_t 、msadsc_t 结构、memarea_t 结构的实例变量 和 MMU页表,所占用的内存空间已经涵盖了内核自身占用的内核空间;
合并内存页到内存区:
现在就让 msadsc_t 结构挂载到 内存区对应的数组中,这样才能提高内存管理器的分配速度;
init_merlove_mem函数作为入口函数,调用merlove_mem_core函数,有两个遍历内存区,
1、确定内存页属于哪个区,标定msadsc_t 结构属于哪个memarea_t 结构;
第一次遍历每个memarea_t 结构,并给msadsc_t结构打上标签,由函数 merlove_setallmarflgs_onmemarea 实现,即属于哪个区;
2、把特定的内存页 合并;挂载到特定的内存区下的 memdivmer_t 结构中的 dm_mdmlielst 数组中;
第二次遍历每个memarea_t结构,合并其中处于相同区的结构,并把它们挂载到 memdivmer_t结构下的dm_mdmlielst 数组中;同时保证两点:一是其中所有的msadsc_t结构挂载到dm_mdmlielst 数组中的合适的bafhlst_t 结构中;二是保证多个msadsc_t 结构有最大的 连续性;由函数merlove_mem_onmemarea 实现,第一就是获取最多且地址连续的msadsc_t 结构体的开始、结束地址、一共多少个msadsc_t 结构体,下一次循环开始的 msadsc_t 结构体的索引号,由函数merlove_scan_continumsadsc实现;第二就是把一组连续的msadsc_t结构体挂载到合适的m_mdmlielst数组中的bafhlst_t 结构中,merlove_continumsadsc_mereabafh函数实现;
初始化汇总:
内存管理数据结构的关系,对于调用次序有严格的规定;函数init_memmgr实现总的调用;
init_msadsc 函数初始化内存页;init_memarea函数初始化内存区;这两个可以交换次序;但是必须是最先开始调用这两个;
init_search_krloccupymm函数初始化内存占用;
init_merlove_mem函数 合并内存页到内存区中;
init_memmgrob 函数;phymmarge_t结构体的地址和数量、msadsc_t结构体的地址和数据、memarea_t 结构体的地址和数量都保存在kmachbsp 变量中,这个变量其实不是用来管理内存的,里面存放的是物理地址;memmgrob_t 结构体用于内存管理;需要将转化为虚拟地址;
总结考虑:当msadsc_t 结构实例变量本身所占用的内存空间会不断增加,怎么降低呢?
增加内存页大小?减少结构体?减少信息?
分配内存
- 面向对象;
- 初始化内存池、申请内存、释放内存三个操作;
- 尽量小的复杂度,优先优化时申请内存时的复杂度;
- 加入单元测试和性能测试
面向对象
?
基本操作
首先,内存池直接返回真实的内存指针,进而无法在代码执行过程中对内存段的位置进行调整,所以空余空间可能很大,但被切开、四散的情况是存在的。这里不考虑这样的情况,需要实现的操作如下:
初始化内存池:直接使用 new 申请一大段空间作为内存池;
申请内存:若长度足够,则从内存池中选择指定长度的连续未使用段返回,并标记该段已使用;否则返回 NULL;
释放内存:查询 ptr 是否是标记的,若是则回收,将该段标记为未使用,并返回 true;若否则返回 false。
首先简单点,看释放内存的操作。使用一个 used[position] 的字典,记录所有指针对应的内存段的大小;释放时直接查询 used 字典,若存在 ptr 指针,则处理,否则直接返回 false。
这里说的处理,即将该段内存由“使用中”标记为“未使用”,并从 used 字典中删除,而并不需要对数组清零(节约时间)。 另外,如果该段内存左右有其他空余的内存段,需要进行合并,为下一次申请大内存做准备。
而申请内存时,最优的操作是找到恰好大于等于当前需要长度的未使用内存段并返回,同时标记该段为“使用中”,内存段长度大于需求长度则进行切分,同样将剩下的部分作为“可使用”的内存段。
如下图所示,内存池一共有 16 个字节。依次申请了 4 个字节、2 个字节、2 个字节和 4 个字节的内存,内存池占用如下图所示:
?
以上是关于07 内存(中)实现内存页面初始化的主要内容,如果未能解决你的问题,请参考以下文章
Linux内存从0到1学习笔记(6.7,物理内存初始化之CMA初始化)