一、proc文件系统
传统意义上的文件系统是用于块设备上信息的存储,/proc这个目录是一个虚拟文件系统,它放置的数据都是在内存当中,所以这个目录本身不占用任何硬盘空间。主要包含如下系统信息:
内存管理
系统进程特征数据
文件系统
设备驱动程序
系统总线
电源管理
终端
系统控制参数
用户和应用程序可以通过proc得到系统的信息,并可以改变内核的某些参数。由于系统的信息,如进程,是动态改变的,所以用户或应用程序读取proc文件时,proc文件系统是动态从系统内核读出所需信息并提交的。下面列出的这些文件或子文件夹,并不是都是在你的系统中存在,这取决于你的内核配置和装载的模块。另外,在/proc下还有三个很重要的目录:net,scsi和sys。 Sys目录是可写的,可以通过它来访问或修改内核的参数,而net和scsi则依赖于内核配置。例如,如果系统不支持scsi,则scsi 目录不存在。
除了以上介绍的这些,还有的是一些以数字命名的目录,它们是进程目录。系统中当前运行的每一个进程都有对应的一个目录在/proc下,以进程的 PID号为目录名,它们是读取进程信息的接口。而self目录则是读取进程本身的信息接口,是一个link。
二、什么是进程
进程通常被定义为一个正在运行的程序实例,它由两个部分组成:一个组成部分是操作系统用来管理程序的内核对象。内核对象是系统用来存放关于进程统计信息的地方。另一个组成部分是地址空间,它包含所有可执行模块或DLL模块的代码和数据。它还包含动态内存分配的空间。如线程堆栈和堆栈分配空间。
进程运行过程,其实就是把磁盘的二进制文件加载(映射)到内存空间中,并且指引CPU去内存中寻址,然后计算,并且返回(I/O)的过程。
可以思考这样一个问题,现在我们硬盘上有三个文件xxx.exe,xxx.apk,xxx,操作系统是如何知道哪些文件是可执行文件呢?操作系统识别可执行文件的方式有两种,一种是在系统内核进行识别(比如linux和windows),另一种是在系统内库层使用虚拟机来实现。使用虚拟机就非常方便,我们可以在不修改内核的情况下修改和扩展虚拟机就可以实现跨平台。
三、进程的运行过程
1、将程序装载到内存(程序的实例化)
32位二进制系统最大寻址能力是 2^32 = 2^10 * 2^2 = 1G * 4 = 4G,所以我们的物理内存最大可以使用4G.假如我们现在同时开了100个进程播放电影,照样可以正常播放,这是为什么呢?事实上除了物理内存外,还有一个虚拟内存
虚拟存储器是一个抽象的概念,它为每一个进程提供了一个假象,每个进程都在独占使用主存(硬盘)
虚拟地址空间如下:
(注:图摘自《深入理解计算机系统》)
地址空间最底部存放用户进程定义的代码和数据,对于所有的进程来说,代码是从同一个固定地址开始。接着就是全局变量和对应的数据位置,堆、共享库、栈。最上面是内核虚拟存储器,内核总是驻留在内存中,是操作系统的一部分,地址空间顶部的区域是为内核保留的,不允许应用程序读写这个区域的内容或者直接调用内核代码定义的函数。
2、读取内存中的程序段内容,给变量分配空间,在调用的时候寻址操作
进程运行过程其实就是把磁盘的二进制文件映射到内存空间中并且指引CPU去内存中寻址,然后计算并且返回(I/O)的过程。
#include <sys/types.h> #include <unistd.h> #include <stdio.h> int main(){ printf("hello PID:%d ", getpid()); printf("hello ppid:%d ", getppid()); char *p; scanf("%s", p); return 0; }启动这个程序(进程)
可以看到这个进程的ID是1634,进程的父ID是1617,下面我们使用命令ps -aux来查看一下当前的进程,该进程的父进程是shell进程。
首先二进制程序getpid被linux系统识别,将该二进制文件放到内存中,处理器寻址并给变量分配内存空间(将函数和变量放到不同的区域),最后将结果输出。
四、进程运行过程中的两个特点
1、多任务,多进程“并发
我们的linux是多任务,分时的,一个独立的逻辑控制流,好像我们的程序独占的使用处理器,下面是CPU的进程调度图。
进程1,2,3,4,5,6......在运行过程中由CPU分配时间片段,上图的处理器就像转盘一样,当指向某个进程后就给该进程分配时间片,开始执行该进程,如此反复。
2、彼此独立、所处的内存隔绝
使用虚拟内存,每个进程都有一个私有的地址空间,好像我们的程序独占和使用内存。
五、进程的生命周期
对程序而言,进程有三大状态:运行、挂起、消亡。
1、建立任务(创建进程)
2、准备运行(等待CPU分配时间片)
3、正在运行(在实际的运行状态中,如果没有分配到cpu实际片,继续等待)
4、挂起(分为可打扰的和不可打扰的),比如scanf等待用户输入就是可打扰中断。
5、消亡(当任务终止,或者被父进程回收)