Chinaunix首页 | 论坛 | 博客
  • 博客访问: 121109
  • 博文数量: 31
  • 博客积分: 2010
  • 博客等级: 大尉
  • 技术积分: 361
  • 用 户 组: 普通用户
  • 注册时间: 2008-03-11 15:38
文章分类

全部博文(31)

文章存档

2008年(31)

我的朋友

分类: LINUX

2008-05-04 21:38:46

     今天学习了0.11核的内存管理机制在这里,先总体说一下0.11核内存管理机制,和一些基本的知识,为后来据分析某个具体函数做准备。

一、页目录项表和页表

     我们知道,I386体系结构的CPU提供了分页机制,它的内存管理是通过页目录项表和页表两级进行的。系统只有一个目录项表,供所有进程共享,里面有1024个页目录项,每个进程又有若干个自己的页表,每个页表记录了1024个物理页地址,一个物理页的大小是4KB,这样I386CPU的最大寻址空间是:1024×1024×40964GB。页表中的每个页表项记录了一个物理页的地址和一些标志信息,页目录项表中的每个页目录项记录了存储某个页表的物理页的内存地址和一些标志信息,这些标志信息中包括三种信息:P,是否可用(也就是,是否有相应的物理页地址);D/A:已修改/已访问;R/W:读写权限。这些信息在后面分析具体函数的时候会用到。

     性地址的转换就是通过这两级表实现的,我前面已经说过CPU实现转换的具体过程。在这里我想说一下,在0.11核中是怎么用程序(软件方式)定位页表,定位物理页的。我们知道一个32位的线性地址分为三个部分,页目录项选择子(10bit),页表项选择子(10bit)和页内偏移地址(12bit)。这样,将这地址右移22位可以得到页目录项选择子,但一个页目录项占4B,所以,要得到页目录项的地址,还要再左移2位(乘以4),这样实际上就是将线性地址右移20位貌似就可得到页目录项地址,但这样做还不行,因为这样得到的地址是目标目录项的地址但不一定是首地址,因为最后2位会产生项内偏移,因此得到目标页目录项的首地址,在右移20位后,再把最低两位清零(与上0xffc)就OK了。得到页目录项后,再将它低12位清零(与上0xfffff000)就可以得到页表的起始物理地址,之所以要将低10位清零的原因和上面的一样,因为一个页表有1024项,每一项有4B,所以,一个页表要占用4K212次方)的物理空间,这样将低12位清零就是为了得到页表的起始地址。在页表中得到页的起始物理地址的做法和在页目录项表中的到页表物理地址的类似,只是利用的是线性地址的中间10位,在这里不再详述。

二、LINUX物理内存的分配

       0.11核的LINUX16MB的物理地址分为了三大部分,由低向高分别是:内核模块区、高速缓冲和虚拟磁盘区、主内存区。用户进程所占的物理内存主要是主内存区。在内核模块区中,线性地址和物理地址是一样的,由低到高分储存着页目录项表、内核使用的四个页表、head.s部分代码、IDTGDT、内核代码。用户进程所占的物理内存就不是这么连续的了,它所占有的数据可以分布在整个主内存区中。对于内存的管理是通过一个mem_map[]的字节数组管理的,它管理着1M-16M这个区间的物理页,数组中的元素的排列和1M以上的物理内存页的排列是一样的,每个元素记录着对应物理页的引用次数(未占用就是0),这样这个数组共有(16M-1M/4K项,其中前面部分是缓冲和虚拟磁盘区在1M以上的部分,而主内存区占用mem_map[]的后(16M-4.5M)/4K项,其中4.5是内核、缓冲以及虚拟磁盘占用的物理内存大小。内存管理就是管理主内存区的页的分配与释放。在初始化的时候,将mem_map[]前部分的缓冲和虚拟磁盘区置为占用,后面的主内存区的置为可用。介于以上划分,在管理内存的时候,要时刻判断操作的内存页是否在有效范围(1M-16M)内。

三、写时复制机制

当父进程利用fork创建子进程的时候,子进程复制了父进程的页目录项和页表,同时将对应的物理页设为只读,这样它们两个共用一段物理内存。当其中的一个进程在自己的虚拟地址范围内进行写操作的时候,就会产生异常,引起中断,中断处理就会在物理内存中再分配一个物理页,并将引起异常的这个页的内容copy进去,并修改对应的页表项,同时将这两个页改为可读写,这样这两个进程就各自有了一个内容相同的物理页了。这就是写时复制机制。

四、需求加载机制

     fork出一个新进程后,通常会用exec为这个进程加载新内容,这个时候,exec()会删除这个进程原有的数据段和代码段占用的页目录项和页表。随后系统会为加载进来的环境参数和命令行参数分配一定物理页和对应的页表和页目录项,除此之外,这个进程的代码和数据没有占用物理内存的任何空间,它门还在磁盘上。但一旦从程序的开始处执行的时候,访问代码和数据的时候,就会发现它们没在内存中,这个时候就会引起缺页中断,中断处理会将在内存中申请一页内存存放数据,并在设置页表中的对应的页表项,如果不存在页表的话,还要申请一页内存存放页表,最后将请求的代码或者数据以块为单位从磁盘上复制到内存中。这就是需求加载机制。

     以上就是0.11核内存管理的基础知识,有了它们,在分析具体的内存管理函数的时候,就很Easy了!

阅读(1180) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~