《操作系统真象还原》chapter8 笔记与警醒
最后更新时间:
读这章遇到的最大的问题就是:“我意会错了这一章想给我讲什么”,以至于整章读完十分困惑,一开始的问题没能解决以至于错过了很多东西,最终效果不是很好……
现在来重新梳理一下本章的内容究竟是在讲什么,解决什么问题。
PART 1
我将makefile、ASSERT、字符串操作,以及位图操作四个小节划分为第一部分,最后一节作为第二部分。
第一部分的内容不多,只涉及一些操作的实现,并没有具体到“欲解决的问题”。因此只需要了解其实现的原理,在以后需要自己手动实现的时候回顾即可。笔者以为不需要对这部分做过多的记录。
不过位图操作的概念和Part 2有一定的联系,因此在这里也需要再提几句。
位图(bitmap)的概念即将”bit位同一个具体事物间建立映射关系,用0和1标识事物的两个状态”。具体到之后的内存管理就是:
以后的内存分配将以“内存页”为基本单位进行分配。建立位图和整块内存的映射关系,用1标识该内存页已被分配,用0标识该内存页未被分配。
建立完成以后,从此便只需要扫描位图中的每个bit就能够得知内存中哪个内存页可用,方便以后进行内存分配。
1 |
|
1 |
|
PART 2
节名“内存管理系统”,但本节所指的内存是“物理内存”,本节管理的对象也是“物理内存”,而不是“虚拟内存”,但因为分页机制已经启用,所以本节所用的地址却是”虚拟地址“。但本节似乎过早的介绍了多进程中”每个进程独享4G地址空间“的概念,以至于我一直以为它接下来会实现这个功能,但结论并非如此,所以我算是扑空了。
本节的逻辑是这样的:
首先为了区分虚拟地址和物理空间,建立了”虚拟地址池“和”物理内存池“。同时,我们将整个物理内存分为”用户物理内存池“和”内核物理内存池“。
此处”建立“一次的过程包括:界定内存池基址、位图清零两个过程。
然后是构建分配机制。
- 从虚拟地址池分配内存页
- 从物理内存池分配内存页
- 建立虚拟地址和物理地址的映射关系
但本节只涉及到了分配,却没用对应的归还操作。也不知道之后几章会不会涉及。
同时需要注意到,本节并未给内核建立独立的页表。我此前一直抱有”不同进程有着相同的虚拟地址“这一问题,也知道这需要通过切换页表来实现,但本节并未实现这个功能,它只是为内核添加了分配内存的能力罢了。具体看如下内容。
笔者认为最后一步是最难理解也最重要的。代码如下:
1 |
|
虚拟地址是根据位图进行分配的,如果每个进程都存在一个位图的话,这里就可能出现相同的虚拟地址,但page_table_add函数是根据虚拟地址来获取pde和pte的,则相同的虚拟地址必然会出现冲突。因此本节并不是在解决这个问题,上面的函数实际实现的是平坦模式下单任务系统的内存分配,也就是在虚拟地址不会出现重复的情况下,为用户和内核分配内存以供其能够动态调整内存的使用。所以这里的”虚拟地址“是 ”无物理地址直接映射的虚拟地址“,而不是 ”虚拟内存空间中的虚拟地址“。理解这一点以后,本节就应该没有其他问题了。
page_table_add的逻辑是:
- 通过虚拟地址得到此地址会被换算到的PDE和PTE
- 如果页目录已经有对应的页表,那么直接把页表项填入物理地址即可建立映射
- 如果页目录本项还未映射到具体的页表,那就申请一块内存页作为新的页表把它写在此PDE处,然后在新页表出写入物理地址
不过读的时候还在好奇为什么能用pte去当memset的参数,其实只需要记住pte是一个虚拟地址,是算出来的,在传入memset的时候还会在MMU中重新计算即可。
PART 3
总结:
本节最终实现的是一个简化的平坦模式下内存分配器。建立的也只是平坦模式下的虚拟地址和物理地址间的映射管理。并未涉及 ”虚拟内存“ 的概,所有地址都应该保证不重复,否则会像double free那样出问题(此处会直接kernel panic)
同时,我们用的是”虚拟地址“,只需要记住我们用到的地址大多都是虚拟地址即可,就不容易出错了。
琐碎:
可能是因为这几天状态很糟糕,每天都处于严重的睡眠不足的情况导致的(春节期间的麻烦太多了),脑子在看书的时候很难集中注意力,以至于会意错了作者的意图……
插画ID:77309888