代码改变世界

内存

2012-08-10 00:46  ggzwtj  阅读(964)  评论(0编辑  收藏  举报

这篇文章要说的是内存管理的数据结构以及这些数据结构的建立方法等问题,首先要区别下面的三种地址:

  1. 物理地址:也就是内存条上的一个一个的单位;
  2. 逻辑地址:段的管理方式中用到,结构为[段描述符:偏移量];
  3. 线性地址:页表管理方式中的地址;   

Linux启动时首先运行在实模式下,这时候EIP中保存的还是物理地址。这时会设置好8MB(2K个页面)空间的页面映射,最低的3位都是1。然后将swapper_pg_dr的地址装入到CR3中,CR0最高位设置为1,这就开启了分页机制。然后通过一个JUMP指令使得EIP的指令从物理地址变成线性地址。这部分的数据结构如下:

在完成内存的探测之后就会用bootmem分配器来管理内存:其实就是根据内存探测的结果建立一个位图。在要分配页面的时候,从bitmap中找到一个没有设置的位即可。在此基础上,我们可以建立进一步复杂、高效的管理结构。该结构的整体结构如下:

这个图中需要注意的节点如下:

  1. per_cpu_pageset用来实现冷热分配器,热页的意思是页已经加载到CPU高速缓存中。其实说白了,更像是free_area之上的一层缓冲。
  2. 页帧是系统内存的最小单位,对内存中的每个页都会有一个page结构体,因此该结构体必须保证足够的小。
  3. 在上面的结构完成之后就不需要bootmem结构了,此时page都会被标记为已使用,然后会去free掉bootmem中的页面,完成后甚至会free掉bootmem本身占用的内存。
  4. zonelist表示的是一个等级表,也就是分配内存的次序。
  5. 伙伴系统管理的是所有内存,不只是内核能访问的1GB的范围。

有了page数组之后,我们发现线性地址和page之间存在着简单的映射关系。但是事实往往不能如愿,伙伴系统的目的是消除碎片,但是碎片总是不可避免的。很可能在需要分配一个较到的内存的时候,虽然剩余的内存很多,但是没办法找到一个足够大的区域(这里的没办法找到是从free_area的角度出发,实际上还是有可能有足够大的空间的),这时候就需要用到间接映射了。