开启辅助访问 切换到窄版

打印 上一主题 下一主题

Linux内存管理模块的简单实现

[复制链接]
作者:冰雪一刀007 
版块:
嵌入式操作系统 linux 发布时间:2021-1-17 17:09:02
13400
楼主
跳转到指定楼层
| 只看该作者 回帖奖励 |倒序浏览 |阅读模式
在bochs上实现内核的fork函数之前,需要先实现内存管理模块。
内存管理模块的初始化函数mm_init,负责根据BIOS读取的扩展内存大小(1M以上内存),初始化物理内存页的管理结构。
get_free_pages和free_pages负责分配和释放一组连续的内存页(至少1个页),按这组内存页的总字节数对齐。
进程的管理结构task和它的内核栈可以绑定在这样的一组内存页上,在fork时需要先调用get_free_pages分配这么一组内存页。之所以把进程task结构和内核栈绑定,是为了current宏可以轻易的获取进程task结构,见文章Linux内核获取当前进程结构的current宏。
kmalloc、krealloc和kfree用于分配不到1个页的小块内存,我们可以把它们分配的最大字节数设置为2048(含小内存块的管理结构)。
用户空间的malloc分配的是虚拟内存,在有代码读写之前并不实际分配物理内存,只是通过移动进程的内存堆(heap)的brk指针,把这段虚拟地址空间设置为可读写。即使有代码读写时,也是在缺页中断的处理函数里往要读写的位置填充1个物理内存页。如果单纯读内存,一般是与父进程共享的。写时复制,需求加载,实际消耗的物理内存并不大。
在内核里,内存还是比较稀缺的。系统内核的很大一部分功能就是怎么让内存使用效率最大化。为了这点,不但有写时复制、需求加载,而且Linux还会把使用频率低的内存页给换到磁盘的swap分区。
简单的内存管理模块,超过半个页的内存都使用get_free_pages按整页分配,不到半个页的使用kmalloc分配。

上图是头文件,声明主要的数据结构和函数。
siska_mm_s,是放在进程的task结构里的内存管理结构,在进程管理时再填充。
siska_page_t,是物理内存页的管理结构,它代表1个物理内存页,暂时只需要一个自旋锁和1个引用计数refs就行。不需要记录具体的物理内存地址,通过它在物理内存管理数组里的索引,就可以算出来。
siska_block_t,是用于kmalloc的小块内存的管理结构。在空闲时,它按照大小挂在不同的链表上,这些链表组成一个数组。包含block结构的大小是2^N字节,N为数组的索引,这时候用size_free变量记录它的大小。
在被使用时,空闲链表元素list就没用了,以size_used表示block的大小,用户数据与block头指针的偏移量为1个long型整数。在C语言里,long与指针的大小一样,指针与机器字长一样,这样可以保证用户数据的对齐与机器字长是一样的。
在32位时以4字节对齐,64位时以8字节对齐,我们设置block在32位时最小是16字节,在64位时最小是32字节。
32位:链表的prev指针和next指针一起占8字节,size_free字段占4字节,12字节对齐到2的幂是16。
64位:链表的两个指针一起占16字节,size_free占8字节,24字节对齐到2的幂是32字节。
操作系统的启动过程
之所以使用双向链表,是删除元素时不需要从表头开始查找,删除速度是O(1)。因为要尽量减少内存碎片,需要把相邻的空闲内存块尽量合并,所以要不断地把小块内存从链表上删除,合并成大块后再挂在另一个链表上,双链表比单链表要快得多。
不管块大小是16字节还是32字节,指针是4字节还是8字节,反正size_used变量的最低2位是没用的,一直是0,除非你把代码跑到16位机上(笑
就算在16位机上最低1位依然是0,我们用它的来记录block是空闲还是正在使用,这样就不需要添加一个额外的标志字段了。因为要按2的幂对齐,少了1个位就是少了1个字节,少了1个字节就是少了4或8个字节。
siska_block_head_t,是kmalloc的连表头,包含一个双链表头和一个自旋锁,后者用来在SMP多核CPU上保护这个链表。单核CPU直接关中断就行。
如果代码运行在用户态,单线程不需要锁,因为中断不会被用户程序处理,多线程可以加mutex互斥锁。内核代码有可能在中断处理函数等没法睡眠sleep的代码中分配内存,所以使用自旋锁。
下图是几个全局变量,注释的部分是我在用户态测试时临时修改的。

在bochs上可以把扩展内存页的管理结构放在1M的位置,然后有多少个内存页就留出多大的字节数。用户态测试时可以直接写死页数。
bochs上可以使用BIOS int 0x15中断检测扩展内存大小,Linux初始化时存在0x90002处。用户态测试时,我直接写了4个页,0x90002在用户程序里是非法地址。
1M以下的基础内存暂时不分配。

siska_block_heads是kmalloc的管理结构,1个哈希数组,4096字节1个页时有12个元素,每个元素都是一个block_head,64位设置最小SHIFT是5,即32字节(1

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表