内核管理进程的虚拟地址空间

当进程需要内存时,内核首先会为进程分配一段虚拟地址,即所谓的Memory Region。由于进程虚拟地址的使用情况记录在vm_area_struct中,所有的vm_area_struct都按照顺序连接在一个链表上,因此寻找某大小的虚拟地址十分简单,扫描这个链表,碰到一块大于或等于[所申请内存大小]的连续地址,便用新的vm_area_struct记录下来,并插到链表的合适位置,这块虚拟地址便被标记为“已用”了。其实这就是操作系统理论里所讲的first fit。早期的Unix就是这样管理物理内存的,而这里用之管理进程的虚拟内存。内核为进程分配内存的步骤如下:
一、找到合适大小的虚拟地址段;
二、向{内存管理子系统}申请物理页帧;
三、在进程页表中建立两者的映射关系。

然而,内核为<自己>分配内存时,只有#第二步#。

没有第三步,是因为一开始的时候,内核页表已经做好了映射。那第一步呢?内核为什么没有像进程一样<<寻找合适大小的虚拟地址段>>这一步骤?

内核自己需要内存时,总是向Slab分配器申请。Slab便为之分配一块连续的内存。内核不需要对这块内存做映射,因为最开始就映射好了。只要这块连续的物理内存在前896M之内,或者从虚拟地址空角度看,这块地址在低端地址范围内。从Slab里分出来后,它就“正式被内核使用”。那么,内核申请内存时得到的虚拟地址是由什么决定的呢?内核没有“额外管理”虚拟内存,具体使用哪一块虚拟内存取决于Slab分配哪块物理内存。Slab分配哪块物理内存又取决于内存管理子系统。
结论是:Buddy System(内存管理子系统)管理了内核的虚拟内存。

严格来说,Buddy System在管理前896M物理内存时随便把内核的虚拟内存也管理了,因为两者是严格映射的。对进程来说,分配虚拟内存与分配物理内存是分开的步骤;对于内核来说,分配了物理内存就等于分配了虚拟内存。内核为自己分配的内存究竟在虚拟内存的什么位置取决于分[配到的内存的页帧]在物理内存中的哪个位置。进程需要额外的结构体记录虚拟内存的使用情况;内核虚拟内存的使用情况就是前896M物理内存的使用情况。换句话说,一旦进程申请到了前896M物理内存中的某一块,就相当于侵占了内核的虚拟地址空间,就相当于内核的这段虚拟地址段不可使用。如果一块物理内存被Buddy System分给了内核,进程是没有机会再得到这块内存的,也就没有机会映射这块内存。如果一块物理内存被Buddy System分给了进程,虽然内核已经预先映射了这块内存,但永远得不到相应的虚拟地址,也自然引用不到相应的表项。这样就避免了两者间的冲突。当然,如果内核有BUG,指针使用不慎,引用了不该引用的虚拟地址,很容易破坏进程的内存。

这样一来,问题都解决了。前896M物理内存由内核与进程混用。但内核只能使用这896M物理内存(因为它的页表映射是固定的),而进程可以使用任何地方的物理内存(因为它的页表可以随意设置)。内核高128M留作其它用途,可以随意映射。内核不能直接使用的内存即“高端内存”。当内核的线性地址空间大于物理内存时,“高端”便不存在了。这种情况实际上有两种可能:一是内核线性地址空间太大,如使用64位系统;二是系统物理内存太小,如机器仅配有512M内存。两者都是内核线性地址空间大于物理内存的结果。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值