免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1197 | 回复: 0
打印 上一主题 下一主题

进程的线性地址空间的管理 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-05-02 13:50 |只看该作者 |倒序浏览
进程地址空间

首先明确两个概念,页和页框。页一般是在线性地址空间里的概念,页既可以表示为4K的线性地址空间,也可以表示为存放在这个地址空间里面的数据(也就是对应的物理页框里面存放的二进制数据单元);而页框是在物理地址空间里的概念,一个页框代表实际物理内存上面4K大小的存储空间,可以想到硬件的分页技术就是将页框映射到页的过程

  • linux为内核线程分配内存(页框)的时候,毫不吝啬,因为它十分信任内核线程,并且默认线程的内存分配的请求完全是正确的,并给予立即的响应,而且针对页也没有任何的保护措施。
  • linux在为用户进程分配内存空间(页框)的时候,异常小气,它认为用户进程对内存的请求是不紧迫的,它不信任用户进程,并且随时准备捕获用户进程引起的寻址错误,比方说:我们在程序里面用malloc动态申请了一段线性地址空间(获得使用权),内核不会马上就为这段线性地址映射物理地址空间(也就是分配实际的内存单元),它会等到你用户真正用到这段地址的时候才会去分配实际的物理内存,具体过程是这样的:用户进程要访问这段线性地址对应的物理地址,因为内核并没有为其分配,用户进程就会发生一个缺页异常,告诉内核“内存中没有我要访问的数据,快点给我加载进来”,这个时候,内核知道自己的伎俩被识破,才开始懒洋洋的调用一个缺页异常处理函数来对进程发送过来的缺页进行处理。把硬盘上的数据加载到物理内存,再将相应的物理地址和线性地址建立好映射关系,哈哈,现在我们的用户进程就又可以继续执行了。

什么情况下才会分配新的线性空间:
  1、执行一个新的进程时,为进程分配线性空间
  2、在进程中exec一个程序,原来的线性地址会被释放,为该进程分配一段新的线性空间(pid也不变)
  3、进程对一个文件进行了“内存映射”,这时会分配一段线性空间来映射这个文件的内容
  4、进程可能需要增加栈的空间,原来的栈空间用完,需要在分配一点空间给进程
  5、进程可能需要创建一个IPC共享线性区来与其他进程共享某些数据
  6、进程通过malloc来申请一段线性区来扩展自己的堆(brk()函数,具体自己去看)
什么时候发生无效线性地址?
  1、编程错误引发的无效线性地址引用
  2、缺页异常引发的无效线性地址
目前为止我们大致了解了一下内核是怎么管理内存的,更加具体的还要看下面:linux-2.6.11
内核中使用的数据结构:

  • 内存描述符:mm_struct,用来描述进程的地址空间相关的信息,所有的mm_struct都放在一个双向链表中
  • 线性区:vm_area_struct,用来描述进程的一个线性区的描述符
  • 内存描述符和线性区的关系:线性区是用来描述进程所使用的一个线性区间的情况,包括线性空间的头,尾和大小等,一个进程可能拥有多个线性区,这些线性区用一个链表链接起来,并且线性地址升序排列;内存描述符其实就是这个链表的一个封装体,不过它加了很多其他的信息,比如线性区个数,计数器,自旋锁等(具体请查看相关书籍)
    线性区的组织方式有两种:一个是链表,另一个是红黑树(这里不细说)

了解上面的概念之后,我们再来看看内核是怎么给进程增加和删除线性区间的

  • 增加:一个进程的线性地址空间是由一个链表来表示的,链表的元素就是线性区,每个线性区应该是有间隔的(如果相邻内核会将其合并),那么增加一个线性区到进程的地址空间,内核检查一个已经存在的线性区可不可以扩展,如果可以扩展,就对其进行扩展,比如有个线性区A大小为10,在其后面距离为100的地方还有一个线性区B大小为50,现在我想申请个70的空间,内核就看线性区A可不可以扩展,显然线性区A后面还有100个单元的空间,可以扩展,因此对其扩展;如果我现在要申请个150的空间,显然线性区A的扩展区是不能满足他的要求的,他会继续往后找,然后在扩展,如果实在找不到,就独立在空闲的线性区间分配一个150的空间,将其链接到进程的线性区链表中。
  • 删除:情况可以分为好几种:将一整个线性区删除:直接删除,将线性区从链表上摘除,我没看过相关删除的代码,感觉应该是这样的:内核应该维持一个空闲线性地址空间的链表,摘除下来的线性区会被放到这个空闲链表中,不是简单放入就可以的,还有对相邻的线性区进行合并等,将线性区相关的标志位置上,表示这个线性区已经没人用了
    只删除线性区的一部分:删除线性区的一部分还会分好几种情况,删除线性区头部,删除线性区的尾部,在线性区的中间进行删除等,删除的步骤应该和上面的大体相似。

缺页异常处理:相当复杂,还是自己看书吧!

请求调页:这里有个权衡的问题,一般进程请求页框的分配有两种处理方法:
1、直接给他分配页框;
2、尽量推迟分配,即他真正需要的时候再分配,这里就需要临时的调页给进程。
考虑方法一:除非你有很大内存,要不然还是别用这种方法(尽管内核线程是这样做的);考虑方法二:可以很好的节省内存的使用,但是临时的调页会浪费大量的CPU时间,这样做划算吗?程序的局部性原理告诉我们,这样做是划算的,程序现在用到的地址在不久的将来用到的可能性是很大的,说明在某段时间内,程序只会访问某段区域的内容,而不会访问其他地址的内容,因此我们可以认为缺页异常是“稀有时间”。
  
fork()方面的内容


  • fork大家都知道它是干什么。父进程创建一个子进程,拷贝父进程所有的代码段,数据段,堆栈段,blablabla...好!现在给你个问题:如果子进程只是简单的对复制过来的信息进行访问,这样做还划算吗?答案很显然:不划算。因为子进程根本就没有对复制来的页框进行修改,那我干什么还要去SB的复制?因此内核采用了COW技术,copy on write。子进程和父进程共享页框,这些页框被标记为只读,当父进程或子进程要对某个页框进行修改,就会触发一个异常,内核会拷贝要修改的页框拷贝到一个新的页框并标记为可写,当其他进程要对这个页框进行写时,内核会检查这个进程是不是这个页框的唯一宿主,若是,才能写。



本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/64950/showart_654866.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP