一、进程定义

进程是一个可执行程序的实例;从内核角度看,进程由用户内存空间和一系列内核数据结构组成,其中用户内存空间包含了程序代码代码所使用的变量,而内核数据结构则用于维护进程状态信息,记录在内核数据结构中的信息包括如下:

  • 与进程相关的标志号(IDs)
  • 虚拟内存表
  • 打开文件的描述符表
  • 信号传递及处理的有关信息
  • 进程资源使用及限制
  • 当前工作目录
  • 大量其他信息

运行进程相关的信息均在/proc/PID/xxx中可以查到

二、进程号

系统中每个进程都有一个唯一标识自己的进程号(PID,pid_t类型),可使用getpid()获取调用进程的进程号,每个进程都有一个自己的父进程,可以使用getppid()获取当前调用进程的父进程PID。所有进程一直往上找自己的父进程,都可以找到所有进程的鼻祖init进程(PID=1)。当父进程终止,其子进程就会变成孤儿进程,init进程就会收养该进程。

进程号分配原则
Linux内核显示进程号需要小于32767,新进程创建时,内核会按照顺序将下一个可用的进程号分配给新的进程使用,每当进程号达到32767的限制时,内核将重置进程号计数器,以便从小整数开始分配,一般重置为300,因为底数值的进程号长期被系统进程和守护进程长期占用,在此范围内搜索尚未使用的进程号只会浪费时间。最大进程号可以通过/proc/sys/kernel/pid_max文件来控制。

三、进程内存分段

Linux系统编程:(2)进程与进程内存布局
c语言编程环境提供了3种全局符号:etext、edata和end,可以允许在程序内使用这些符号以获取相应程序的text段、data段和bss段结尾处下一个字节的地址,必须显示:extern char etext, edata, end;

Linux系统编程:(2)进程与进程内存布局
Linux系统编程:(2)进程与进程内存布局
其中,函数局部变量、参数及返回值均属于stack中。

四、进程虚拟内存管理

Linux像大多数现代内核一样,采用虚拟内存管理技术,该技术利用了大多数程序的一个典型特征,即访问局部性,以求高效利用CPU和RAM(物理内存)资源,大多数程序都展现了两种类型的局部性:

  • 空间局部性:指程序倾向于访问最近访问过的内存地址附近的内存
  • 时间局部性:指程序倾向于在不就的将来再次访问最近刚访问过的内存地址(循环)、

正是由于程序局部性,使得程序仅有部分内存地址空间存在于RAM中,依然能够正常执行。

虚拟内存技术将每个进程使用的内存切分成小型的、固定大小的“页(page)”单元,将RAM划分成一系列与虚拟内存页尺寸相同的“页帧”。任何时刻,每个进程仅有部分页需要驻留在物理内存页帧中,这些驻留的页构成了驻留集,进程未使用的页拷贝保存在交换区内----这是磁盘空间的保留区域,作为计算机RAM的补充,仅在需要的时候才会载入物理内存。若进程访问的页面目前尚不存在于物理内存,将会发生页面错误,内核会挂起进程的执行,同时从磁盘中将该页面载入内存。

为了满足上述的功能,内核需要为每个进程维持一张页表(page table),页表描述了每页在进程虚拟地址空间的位置(可为进程所有的虚虚拟内存页面的集合)。页表中的每个条目要么可以指出一个虚拟页面在RAM中的实际位置,要么表明其当前驻留在磁盘上。

Linux系统编程:(2)进程与进程内存布局

虚拟内存的实现,需要硬件中分页内存管理单元(PMMU)的支持,将每个虚拟内存地址转换成相应的物理内存地址,当特定虚拟内存地址所对应的页没有驻留在RAM中,将以页面错误通知内核。

虚拟内存地址空间与物理地址空间隔离优点

  • 进程与进程、进程与内核相互隔离,一个进程不能读取或者访问另外一个进程或者内核的内存。这是因为每个进程的页表条目指向RAM(或交换区)中截然不同的物理页面集合。
  • 适当情况下,多个进程能够共享内存。这是由于内核可以使不同进程的页表条目指向相同的RAM页,例如同一程序的多进程共享代码副本;或者调用mmap或者shmget系统调用显示请求与其他进程共享内存区,这有利于进程间通信。
  • 因为需要驻留在内存中的仅是程序的一部分,所以程序加载都很快,且允许进程所占用的内存能够超出RAM容量。

相关文章: