Linux环境下进程基本概念复习

一、进程地址空间概述

                                                                          图1-1 虚拟地址空间内存布局

图1-1是描述linux虚拟地址空间的大致内存布局,地址空间大小为4G,0-3G内存为用户空间,3-4G空间为内核空间,一个进程只能读写用户空间,而不能对内核空间进行操作,内核空间是可以被多个进程共享的,这个在后文中会提到。

由低地址向高地址,依次为:

① 0-128M预留空间:这里是地址空间的最低部分,未赋予物理地址。禁止访问,它用来捕捉使用空指针和小整型值指针引用内存的异常情况;

② 正文代码段txt:存放程序用于执行的代码,即CPU机器指令,通常属于只读,以防止其他程序意外地修改这一部分指令(对该段的写操作将导致段错误);

③ 已初始化数据data:数据段,映射程序中已经初始化的全局变量;

④ 未初始化数据bss:

  • 程序中的未初始化的全局变量和静态局部变量;
  • 初始值为0的全局变量和静态局部变量(依赖于编译器实现);
  • 未定义且初值不为0的符号;

⑤ 堆区:存放进程运行时动态分配的内存,由程序员自己管理进行动态扩张或缩减,通过malloc/new可以申请内存,free/delete用来释放内存,堆的地址从低向高扩展,是不连续的空间;

⑥ 共享库:共享库及匿名文件的映射区域;

⑦ 栈区:记录函数调用过程的相关信息,栈的地址从高地址向低地址扩展(不同于堆区是向上扩展,栈区是向下扩展),是连续的内存区域;

⑧ 命令行参数和环境变量,在linux下通过键入env命令可以查看系统定义的环境变量;

⑨ 内核空间:每个进程在内核中都有一个进程控制块(PCB)来维护进程相关的信息,Linux内核的进程控制块PCB是一个task_struct结构体变量。这里不对PCB进行赘述。

操作系统中对虚拟地址空间的管理是以页为单位的,1页=4096字节=4KB

举例:malloc在堆区申请1000Bytes的空间,向物理内存申请真正地址1页的大小。此时若再malloc 200Bytes,操作系统发现已分配的1页=4096Bytes还未使用完,不再向物理内存申请,而若再malloc 3097Bytes,发现1页大小不够用,则重新申请1页的地址空间。

这有利于我们提高编程的效率,在不知道申请的地址空间大小的情况下,最好是4096的整数倍,这样避免了空间的浪费,或者多申请了一页的地址空间,浪费了系统资源,因为申请地址空间也是需要时间的。

二、进程运行前准备举例

                                                          图1-2 磁盘文件加载到物理内存再映射到虚拟内存中

图1-2简单描述了一个磁盘文件加载到物理内存再映射到虚拟内存中的过程,映射的过程由操作系统维护一张虚拟内存映射表来进行。进程1运行前,首先将代码加载到物理内存中,然后映射到虚拟内存中初始化一系列变量,进程2有同样的过程。对于两个进程不同的是,他们的用户空间0-3G不共享,而内核空间3-4G因为内核代码不允许用户对其有所改动,所以可以实现共享,这样做也节省了物理内存的空间。

Q:为什么内核空间禁止修改?

A:通过R/W访问控制属性对其进行访问控制,内核空间的代码设置为只读,而用户空间的内容可写可读,这一原理同C语言中,输入 char * p = "hello";  不能使用*p对字符串进行修改,字符串存放在只读数据段中,在申请内存时页面属性为“只读”,内核区同样也是“只读”的属性。

三、进程运行状态

                                                                                 图1-3 进程的状态

操作系统中进程的基本状态分为:运行、就绪、阻塞3个状态。

① 运行态(进程实际占用CPU);

② 就绪态(可运行,等待CPU分配时间片);

③ 阻塞态(等待外部事件发生进入就绪态,如等待键盘输入)。

前两种状态处于的状态都是可运行的状态,CPU在运行时采用轮换时间片的机制,以单核CPU为例,CPU不会一直运行某一进程直到他结束为止,而是分为一些固定的周期,以时间片为单位,轮换运行不同的进程,但这个切换的时间非常短,导致单核CPU给人一种并行运行的错觉,实际上是一种伪并行。

从运行到阻塞:进程因为需要等待外部事件(如输入)而阻塞;

从阻塞到就绪:进程等到了外部事件(出现了有效输入),进入就绪态;

从就绪到运行:CPU调度程序分配给了进程时间片,进程开始运行;

从运行到就绪:进程占用CPU达到一定时间,需要将CPU时间片让出给别的进程使用;

三种状态都能直接变为停止的状态,如:出现外部中断,系统错误,或者被其他进程发送信号杀死

例:假设有两个程序a.out和b.out,a.out正在运行,而b.out处于就绪态,在调度程序切换进程时,a.out运行中断,保存处理器现场(一些运行时用到的变量和寄存器的值)到PCB中的内核栈(注意不是0-3G的用户栈),由b.out使用CPU,a.out切换回时,在自己的内核栈中找到之前保存的内容,恢复处理器现场,a.out继续运行,由操作系统完成这个进程调度的过程,称为分时复用。

猜你喜欢

转载自blog.csdn.net/qq_37348221/article/details/101263224