程序员的自我修养--可执行文件的装载与进程

来源:互联网 发布:apk优化 编辑:程序博客网 时间:2024/05/21 04:21

进程的虚拟地址空间

  1. C语言指针大小的位数与虚拟地址空间的地址位数相同,即32位平台下进程的虚拟地址空间为4G
  2. 由于程序在运行是处于操作系统的监管下,进程的虚拟地址空间都在操作系统的掌握中,只能使用操作系统分配给进程的地址。如果访问未经允许的地址,将会强制结束进程。一般在linux上回出现Segmentation fault
  3. 在32位平台中,整个4 GB被划分成两部分,其中操作系统本身用去了一部分:从地址0xC00000000到0xFFFFFFFF,共1 GB。剩下的从0x00000000地址开始到0xBFFFFFFF共3 GB的空间都是留给进程使用的。那么从原则上讲,我们的进程最多可以使用3 GB的虚拟空间,也就是说整个进程在执行的时候,所有的代码、数据包括通过C语言malloc()等方法申请的虚拟空间之和不可以超过3 GB
  4. 通过窗口映射的方式将高于4G的物理内存进程的虚拟地址空间中,linux中采用mmap的系统调用实现

装载方式

  1. 动态装入:根据程序的局部性原理,将程序最常用的部分装入内存,不太常用的放到磁盘中
  2. 覆盖转入:程序员编写覆盖管理器,手工将程序分割成若干块,然后编写一个小的辅助代码来管理这些模块何时应该驻留内存而何时应该被替换掉
  3. 页映射:是虚拟存储机制的一部分,物理页与虚拟空间中的页大小相同,通过存储管理器进行调度虚拟页到物理页中

从操作系统角度看可执行文件的装载

1.进程的建立的三步:

  • 创建一个独立的虚拟地址空间(创建映射函数需要的数据结构,建立虚拟空间与物理内存映射关系)
  • 读取可执行文件头,并且建立虚拟空间与可执行文件的映射关系(建立虚拟空间与可执行文件之间的关系)

当程序发生页错误的时候,操作系统将从物理内存中申请物理页空间,然后将“缺页”从内存中读到磁盘中,设置虚拟页与物理页之间的映射关系。当发生缺页错误的时候,通过虚拟地址空间与可执行文件之间的映射关系获取需要在相应页在可执行文件中的具体位置

  • 将CPU的指令寄存器设置成可执行文件的入口地址,启动运行

2.页错误

当发生页错误的时候,操作系统首先找到空页面所在的VMA,计算出相应页面在可执行文件中的偏移量,在物理内存中分配一个物理页面,将虚拟页面与物理页面之间建立映射关系,把控制权交还给进程,进程从刚才页错误的位置开始执行。

进程虚存空间分布

1.ELF文件链接视图和执行视图
在ELF文件被映射的时候。每个section在映射的时候长度都是该系统页长度的整数倍,如果不是,则多余的部分将会占用一个页,这种情况就会导致大量的内存碎片。

为了解决上述问题,操作系统将相同权限的section合并到一起当做一个segment进行映射,在映射之后在进程的虚拟地址空间中只有一个对应的VMA,在ELF文件中专门有一个程序头表用来保存Segment信息。

这里写图片描述

2.堆和栈
操作系统通过使用VMA来管理虚拟地址空间,除了用来映射各个segment,还可以用来管理栈、堆等空间。例如如下的elf文件和虚拟地址空间之间的映射关系:
这里写图片描述

上图中需要注意的是对于“.bss”和“__libcfreeres_ptrs”部分没有映射到文件,通过do_brk()将“.bss”和“__libcfreeres_ptrs”剩余部分映射到堆栈中。

3.堆空间的最大申请数量
具体数值是受到操作系统版本、程序大小、程序栈数量等的限制,甚至有些每次运行的结果不同。

4.段地址对齐
由于段地址对齐的方式会在文件段的内部出现很多的碎片,导致磁盘的浪费。操作系统通过让各个segment接壤的部分共享一个物理页面,将该页面分别映射两次来解决,如下图:
这里写图片描述

阅读全文
0 0
原创粉丝点击