文档章节

可执行文件的装载与进程 1

谁染霜林醉
 谁染霜林醉
发布于 2014/09/13 15:42
字数 1635
阅读 106
收藏 1

1.地址空间

单就程序来讲,是一个静态的概念,它是一些被预先编译好的指令和数据,存放到了一个或多个文件中,只有装载到内存后才被运行起来。被装载后成为

一个进程,是一个动态的概念,进程是程序运行时的一个过程。

每个进程都有自己独立的虚拟地址空间,这个空间的大小是由CPU的位宽来决定的,比如32位的CPU可寻址空间是2的32次方,即4G空间;64位的CPU可

寻址空间是2的64次方的空间。具体是多少,可以通过C语言的指针大小来判断,因为一般来讲C语言的指针大小与虚拟空间的位数是相同的。

但我们每个程序并不能使用完全的这些空间,对Linux下的进程来讲,理论上程序只能使用3G的大小。

在这4G的虚拟空间中,kernel用掉了1G的空间;程序的进程用掉了3G。进程中程序的数据 指令 以及 像malloc申请的内存,都在这里面分配。

现在的大型程序,如大型游戏,大型数据库等已经不能满足了。

但事实上,3G的空间也不是完全可以使用的,还有一部分是预留出来的。

那么在32位的平台中无法使用超过4G的虚拟空间,实际上能否使用呢?实际上还是可以的。

如果CPU的地址线超过32根,那么就可以访问实际的超过4G的物理内存了,比如intel的奔腾pro系列就可以访问64G的空间,因为他有36根地址线。

这种方式叫做PAE,就是物理地址扩展。如图:

我们在虚拟空间中分配一块出来,用来映射高于4G空间的内存。用到A时映射到A,用到B时映射到B。这样就能使用多于4G的空间了。

2.装载方式

程序必须要装入内存中才能正常运行,最简单的就是将程序全部装入内存,单事实来说,内存根本无法完全将程序存下。

这时候就需要动态装入这一技术,即将常用的放入内存,不太常用的放到磁盘。

装载方式有 覆盖装入 与 页映射 2种方式。思想就是根据程序的局部性,将用到的使用频率高的放入内存,不用的使用频率低的放在硬盘。

现在主要的方式是页映射的方式。

页映射的方式就是将程序按一定的大小分成一个一个的页,windows下常见的就是4K。

假如程序装载后已经运行,一段时间后程序需要P1这一页,这时候就得从内存中删除一页,来装载P1。

删除算法有很多种,最常用的的FIFO 先入先出,LUR 最少使用等。

3.可执行文件的装载

在上面可以看到,如果要移除并重新页映射的话,在真实的地址上,势必要重新定位地址。但是现在有了虚拟地址,可以通过MMU这一硬件来自动完成

地址转换的功能。

3.1进程的建立

一个进程独特的特征是拥有独立的虚拟空间,这样使他有别于其他进程。

进程的创建一般需要3步:

①创建一个独立的虚拟空间

②读取文件头,映射虚拟空间与可执行文件

③将CPU指令寄存器设置成可执行文件的入口地址,开始执行。

第一步创建虚拟空间:

虚拟空间是由一组映射函数,将虚拟空间各个页,映射到物理空间。那么创建虚拟空间就是创建映射函数需要的数据结构。

实际在x86的Linux下,只创建一个页目录就可以了,实际的映射关系到发生页错误的时候,再去设置。

注意:所谓页错误,是没有映射的空白页,并不是普通认知的错误。

第二步映射文件

这一步是将虚拟空间和可执行文件映射起来。

在 第一步 的基础上,操作系统在发生缺页,即页错误时,会去分配一个物理页与虚拟空间对应起来,再加载程序到内存。那么应该加载物理磁盘上的哪一页呢?

这就需要我们这一步的虚拟空间和在磁盘上的可执行文件的映射关系。

假设有一个可执行文件,他仅有text段,且大小不足4K。那么他的映射关系:

即使不足4K,那么也将占用4K的空间。

这种映射关系保存在操作系统内部的一个数据结构,Linux叫做虚拟内存区域(VMA)。

操作系统创建进程后,会在进程相应的数据结构中设置一个text段的VMA:

在虚拟空间中,地址是0x08048000-0x08049000,对应ELF文件的text段,属性是只读等。

第三步设置CPU指令寄存器为可执行文件入口,开始执行

从程序角度来看,这一步很简单,就是从文件头中的程序入口地址开始执行程序。但是从操作系统来说,很复杂。

比如从内核堆栈切换到用户堆栈,切换CPU运行权限等操作。

3.2页错误

从上面可以知道【第一步创建虚拟空间】时,只是填充了映射关系目录,并未有实际的映射关系。

以上面的例子来讲,程序的入口地址是0x08048000,当CPU开始执行时,发现这是一个空白页,那么就是一个缺页,也就是页错误。

那么操作系统就会处理这种情况(因为是很容易发生的,所以有专门的处理机制),并根据上面【第二步】的映射关系,分配物理内存,找到文件

中对应的页,装入内存,并将控制权交给程序,从刚才出现页错误的地方开始重新运行。


暂时到此。


© 著作权归作者所有

谁染霜林醉
粉丝 3
博文 15
码字总数 18432
作品 0
济南
程序员
私信 提问
从零开始UNIX环境高级编程(7):进程环境

0. 引言 在学习进程控制前,先了解进程运行的环境,如:main函数是如何被调用的;命令行参数是如何传递给新程序的;程序在内存空间中是什么样的结构;进程的终止方式等。 1. main函数 1.1 程...

伤口不该结疤
2017/04/24
0
0
linux 目录介绍

linux 目录介绍; /bin : 包含供每个人使用的可执行程序; /sbin: 包含仅供管理员使用的可执行程序; /lib : 包含库文件; /boot:包含内核镜像 和其他相关内容; /dev : 包含硬件外设;...

韩A
2017/04/18
0
0
Greenplum中装载和卸载数据

装载和卸载数据 GP装载概述 关于外部表 1) 外部表允许用户像访问标准数据库表一样访问外部表 2) 结合GP的并行文件分配程序(gpfdist),外部表支持在装载和卸载数据时全并行化利用所有segment...

fortyone41
2016/07/21
0
0
浅析Linux计算机进程地址空间与内核装载ELF

简介: 本文基于Linux™系统对进程创建与加载进行分析,文中实现了Linux库函数fork、exec,剖析内核态执行过程,并进一步展示进程创建过程中进程控制块字段变化信息及ELF文件加载过程。 一、...

nop4ss
2015/10/10
198
0
内存管理之用户空间

32 位的平台上,线性地址空间为固定的 4GB,并且由于采用了保护机制,Linux内核将这 4GB 分为两部分,线性地址较高的 1GB(0xC0000000 到 0xFFFFFFFF )为共享的内核空间;而较低的 3GB 为每...

Tanswer_
2017/12/10
0
0

没有更多内容

加载失败,请刷新页面

加载更多

PostgreSQL 11.3 locking

rudi
今天
5
0
Mybatis Plus sql注入器

一、继承AbstractMethod /** * @author beth * @data 2019-10-23 20:39 */public class DeleteAllMethod extends AbstractMethod { @Override public MappedStatement injectMap......

一个yuanbeth
今天
13
1
一次写shell脚本的经历记录——特殊字符惹的祸

本文首发于微信公众号“我的小碗汤”,扫码文末二维码即可关注,欢迎一起交流! redis在容器化的过程中,涉及到纵向扩pod实例cpu、内存以及redis实例的maxmemory值,statefulset管理的pod需要...

码农实战
今天
4
0
为什么阿里巴巴Java开发手册中不建议在循环体中使用+进行字符串拼接?

之前在阅读《阿里巴巴Java开发手册》时,发现有一条是关于循环体中字符串拼接的建议,具体内容如下: 那么我们首先来用例子来看看在循环体中用 + 或者用 StringBuilder 进行字符串拼接的效率...

武培轩
今天
9
0
队列-链式(c/c++实现)

队列是在线性表功能稍作修改形成的,在生活中排队是不能插队的吧,先排队先得到对待,慢来得排在最后面,这样来就形成了”先进先出“的队列。作用就是通过伟大的程序员来实现算法解决现实生活...

白客C
今天
87
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部