1、进程和程序
程序是包含了一系列信息的文件,这些信息描述了如何在运行时创建一个进程
程序包含如下信息:
- 二进制格式标识:描述可执行文件格式的元信息(metainformation),内核利用此信息来解释文件中的其他信息。大多数UNIX实现采用可执行连接格式ELF
- 机器语言指令
- 程序入口地址
- 数据
- 符号表及重定位表
- 共享库和动态链接信息
进程是由内核定义的抽象实体,并为该实体分配用以执行程序的各项系统资源
进程又用户内存空间和一些列内核数据结构构成。
用户内存空间包含了程序代码及所使用的变量。内核数据结构用于维护进程状态信息:
- ID
- 虚拟内存表
- 打开文件描述符表
- 信号传递及处理的有关信息
- 进程资源使用及限制
- 当前工作目录
2、父进程和子进程
init进程进程号为1,是所有进程从始祖
Linux内核限制进程号需要小于等于32767,新进创建时,内核会按顺序将下一个可用的进程号分配给其使用,当达到限制时,内核将重置进程号计数器,以便从小整数开始分配,一般 会从300开始分配,因为低数值的进程号为系统进程和守护进程所长期占用
pid_t getpid(void) // 当前进程号
pid_t getppid(void) // 父进程号
pstree(1) // 查看进程树
3、进程内存布局
- 文本段
- 初始化数据段:全局变量、静态变量
- 未初始化数据段(BSS段):未初始化的全局变量、静态变量
- 栈
- 堆
size(1) // 显示二进制可执行文件的文本段、初始化数据段、bss的段大小
应用程序二进制接口(ABI)是一套规则,规定了二进制可执行文件在运行时如何与某些服务(诸如内核或函数库所提供的服务)交换信息,ABI特别规定了使用那些寄存器和栈地址来交换信息以及所交换值的含义,一旦针对某个特定的ABI进行了编译,其二进制可执行文件应能在ABI相同的任何系统上运行。与之相反,标准化API(如SUSv3)仅能通过编译源代码来保证应用程序的可移植性
C语言提供3个全局符号(symbol):
- etext
- edata
- end
获取程序文本段、初始化数据段和非初始化数据段结尾处下一个字节地址
4、虚拟内存管理
虚拟内存管理技术,一个特征,即访问局部性
- 空间局部性:程序倾向于访问在最近访问过的内存地址附近的内存
- 时间局部性:程序倾向于访问在不久的将来再次访问最近刚访问过的内存地址
虚拟内存划分为页
RAM划分为与虚拟内存页尺寸相同的页帧
内核维护一张页表,页表描述了每页在进程虚拟地址空间中位置映射到RAM中的位置
虚拟内存管理带来的优点
- 进程与进程、进程与内核相互隔离
- 适当情况下,多个进程能够共享内存(进程的页表可以指向相同的RAM页)
- 执行同一程序的多个进程,可共享一份(只读)程序代码副本
- 进程使用shmget()和mmap()系统调用请求与其他进程共享内存区,处于进程间通信目的
- 便于实现内存保护机制,对页表条目标记可读、可写、可执行
- 加载快,虚拟内存要大于RAM容量,提高CPU利用率
5、栈和栈帧
函数的调用和返回使栈的增长和收缩呈线性,栈驻留在内存的高端并向下增长(朝堆的方法)。专用寄存器——栈指针用于跟着当前栈顶
用户栈包含的信息
- 函数实参和局部变量
- 函数调用的链接信息
6 命令行参数
int argc
char *argv[]
argv[0]包含了调用程序的名称,gzip(1) gunzip(1) zcat(1) 是同一个程序和它的多个链接,程序根据arg[0]的不同来执行不同人物
7 环境列表
每个进程都有与其相关的环境列表的字符串数组,是键值对。新进程创建时,会继承其父进程的环境副本,这是原始的进程间通信方式。
用途:shell通过环境变量给它创建的所有子进程传递信息
$ export // 查看环境变量
$ export SHELL = /bin/bash // 添加环境变量
c语言中使用全局变量char **environ
访问环境列表
getenv(char *name) // 获取指定环境变量
putenv() // 修改
setenv() // 修改
ensetenv() // 移除
### 8执行非局部跳转 setjmp()和longjmp()
非局部跳转:跳转的目标为当前执行函数之外的某个位置,类似于goto语句