*操作系统:计算机系统包含的一个基本的程序集合。
- 内核(进程管理、进程调度、进程间通讯机制、内存管理、中断异常处理、文件系统、I/O系统、网络部分)
- 其他程序(函数库、shell程序)
*操作系统的目的 - 与硬件交互,管理所有的硬件资源
- 为用户程序即应用程序提供良好的运行环境。
进程
^系统方面:
- 程序的一个执行实例
- 正在执行的程序
- 能分配处理器并由处理器执行的实体
^内核方面:
- 担当分配系统资源的实体
^两个基本元素:
- 程序代码
- 和代码相关的数据集
^进程是一种动态描述,不是所有的进程都在运行
进程描述
^所有的进程信息都被存放在进程控制块的一个数据结构中
^进程控制块(PCB)
linux中 task_struct是内核的一种数据结构,会被装载到RAM里并包含着进程信息。
标识符
状态
优先级
程序计数器
内存指针:
- 包含程序代码和进程相关数据的指针
- 和其他进程共享的内存块的指针
上下文数据:
- 程序执行时处理器的寄存器中的数据
I/O状态信息:
记账信息:
所有运行在系统里的程序都以task_struct链表的形式存在在内核里。
进程状态切换
^运行态并不意味着一定在运行状态,他表示 进程要么在运行中要么在运行队列里。
^僵尸进程(zombies),进程退出但是父进程没有读取到子进程的退出码就会产生僵尸进程。
进程位置
1.进程内存映像
程序执行的时候,操作系统将可执行程序复制到内存中,程序转换为进程需要以下步骤:
^内核为该进程分配进程标识符PID以及其他系统资源。
^内核将程序读入内存,为程序分配内存空间
^内核为该进程保存PID即相应状态信息,把进程放到运行队列中等待执行。程序转化为进程后就可以被操作系统的调度程序执行了。
*进程的内存映像:内核在内存中如何存放可执行程序。
* 布局如下:
2.进程映像的位置依赖于使用的内存管理方案。
3.可执行程序与进程的内存映像的不同之处:
- 可执行程序位于磁盘中、内存映像位于内存。
- 可执行程序没有堆栈,程序被加载到内存中才会分配堆栈。
- 可执行程序也有未初始化数据段,不被存储在位于硬盘中的可执行文件中。
- 可执行程序是静态的、不变的,内存映像随着程序的执行是 在动态变化的。
进程优先级
^进程CPU资源分配就是指进程的优先权(priority)。优先级高的进程有优先执行的权利。
PRI:表示优先级,值越小越早被执行。
NI:代表这个进程的nice值。
NI不是进程的优先级但会影响进程的优先级。PRI(new)=PRI(old) + nice。
修改进程优先级的命令有两个:nice,renice
1 一开始执行就指定nice的值:nice
nice -n -5
等级范围从-20 - 19 。-20 最高,19 最低。
2 调整已存在进程的nice:renice
renice -5 -p 5200:将PID为5200的进程的nice设为-5。
renice指令可重新整理程序执行的优先权。
^参数:
-g<程序组名称> 修改所属组的程序的优先权
-p<程序PID> 改变该程序的优先权
-u <用户名称> 修改所属于该用户的程序的优先级。
^只有系统管理才能修改优先权。
2.1 也可用top命令更改已存在进程的优先级。
进程执行
^进程执行时,会被装载到虚拟内存,为程序变量分配内存,把相关信息添加到task_struct里。
^进程内存分布布局:
- 文本段:程序员指令
- 数据段:静态变量
- 堆:动态内存分区区域
- 栈:动态增长与收缩的段,保存本地变量。
^两种创建进程的办法:fork()和execve()。都是系统调用,只是运行方式有点不同。
fork()创建子进程。紫禁城会得到父进程数据段、堆段和栈段的一份拷贝,子进程可以随意修改这些内存段。但是文本段是父子进程共享的,子进程不能修改。
execve()创建新进程。系统调用会销毁所有的内存段去重新创建一个内存段。但execve()需要一个可执行文件或者脚本作为参数。
*execve() 和 fork() 创建的进程运行的都是进程的子进程。
^僵尸进程:一个子进程在其父进程没有调用wait() 或者 waitpid()的情况下退出 。如果其父进程还存在且一直不调用wait,该进程将无法回收,等到父进程退出后,该进程将被init回收。
^孤儿进程:一个父进程退出,但他的一个或者多个子进程还在运行,子进程将为孤儿进程。孤儿进程将init进程 (1号进程)所收养,并由init进程对他们完成状态收集工作。
进程环境
^进程终止:(8种,前5 正常)
1 main函数返回。
2 调用exit函数。
3 调用_exit或_Exit。
4 最后一个线程从启动例程返回。
5 最后一个线程调用pthread_exit;
6 调用abort函数;
7 接到一个信号并终止;
8 最后一个线程对取消请求作出响应。
^环境表
每个程序都会收到一张环境表。环境表是一个字符指针数组,每个指针指向一个以NULL结尾的环境字符串,环境指针environ是一个全局变量,指向指针数组的地址。
通常呀getenv 和 putenv 函数来访问特定的环境变量,而不是environ全局变量。
栈帧
^堆栈是记录调用路径和参数的空间
》函数调用框架
》传递参数
》保存返回地址
》提供局部变量空间
^利用堆栈实现函数调用和返回
*堆栈相关寄存器
》esp 堆栈指针(stackpointer)
》ebp 基址指针(base pointer )
*堆栈操作
》push( 栈顶地址减少四个字节32位)
》pop (栈顶地址增加四个字节)
*ebp 在c语言中 记录当前函数调用基址