进程概念介绍
每次写笔记的时候总有一种想法,担心这个观点是错误的.担心我学到的内容是问题了,从而给看笔记的同学们传递一种错误的知识.希望看笔记的同学带疑惑的去看去思考,我写的是不是有问题,发现错误了希望您也能反馈给我.我也从中学到得到.
什么是进程
了解进程之前,需要先了解一下什么是程序,程序就是一个存放在磁盘的有序指令集合,是静态的;而进程可以简单理解成磁盘中程序的一个副本,只不过这个副本时动态的,运行台内存空间中.而且一个进程不单单只运行你指定的运行程序的代码或部分代码,还包括了程序运行时需要的各种库文件和数据信息.
同时还要一个概念那就是线程,线程是计算机CPU调度的最小单位,一个进程中可能包含一个线程,也可能包含多个线程.线程就好比公司的员工,而进程就相当于一个公司,一个小公司可能老板和员工是同一个人,同样的小进程中就只有一个线程,有的公司还有很多员工,同样进程也可能有很多线程同时工作.
进程的组成结构
进程是在进程队列task list中调度进程的,进程队列又是由一个一个的进程结构体task_sturck组成的双向循环结构.可以说一个进程结构体就管理着一个进程,所以这种进程结构体又称为进程控制块
一个进程结构体中包含:
进程的ID 用户ID 和组ID
程序计数器
进程的状态:就绪态 执行态 睡眠态 阻塞态
进程切换时需要保存和恢复的CPU寄存器中的值
描述虚拟内存分配的地址信息
描述控制终端的信息
当前工作目录
文件描述符表,包含很多指向file结构体的指针
进程可以使用的资源上线
输入输出状态:配置进程使用IO设备
进程眼里的天地:虚拟内存空间
进程是运行在虚拟内存空间的,在进程眼里虚拟内存就只有自己和内核.自己完全享有内核和CPU等硬件资源.
如下图是以32为系统为例,进程以为自己完全享有0-3G的虚拟内存,3G-4G内存是内核占有的.进程可供自己完全支配的这部分空间称为用户空间,内核占有的那部分空间称为内核空间.
用户空间划分为五个段:
代码段:Text Segment,这里存放了进程执行时需要用到的代码.所以这部分是只读的.
数据段:Data Segment,这里用来存放已经初始化且值不为0的全部变量和静态局部变量
BSS段::Block Started by Symbol,存放了未初始化或者已经初始化但是值为0的全局变量和静态局部变量
堆:heap,用于存放数组和对象,堆是用来存放进程运行中被动态分配的内存段,它的大小不固定,可动态扩展或酸碱,单进程调用malloc等函数分配内存时,新分配的内存就被动态添加进堆中,当利用free函数释放内存时,就是从堆中剔除该内存.同时因为在不断的malloc 和free这部分内存空间是不连接的,所以堆是用链表结构来储存数据的.
栈:stack,栈是用来存放新创建的局部变量和函数参数,参数返回值.由于栈的后进先出特性,栈特别方便用来保存恢复调用现场,即某个进程运行中产生在CPU寄存器中的数据.
内核空间:
内核空间是属于操作系统的一部分常驻内存,操作系统不允许普通用户的应用程序读写这个区域的内容或者直接调用内核空间中定义的函数.
虚拟内存和物理内存的关系:
存放进程的虚拟内存最终会映射到物理内存当中.物理内存是怎么分配的呢?
操作系统会把物理内存划分成一个一个的页框,页框的大小一般是4k,可以使用
Getconf -a | grep -i size 来搜索查看page 的大小.
[root@CentOS7 411]# getconf -a | grep -i size PAGESIZE 4096 PAGE_SIZE 4096 SSIZE_MAX 32767
在进程看来虚拟内存是连续的,而物理内存分配的内存页不一定是连续的,就会出现一种出现一种奇怪的映射关系,虚拟内存可能对应这多个不连续内存页
可以使用pmap命令来查看某个程序的具体物理地址映射表.也可以通过查看/proc/目录下对应PID目录中的maps文件
[root@CentOS7 proc]# pmap 863 863: /usr/sbin/sshd -D 000055ceab69c000 800K r-x-- sshd 000055ceab963000 16K r---- sshd 000055ceab967000 4K rw--- sshd 000055ceab968000 36K rw--- [ anon ] 000055ceac9a4000 132K rw--- [ anon ] 00007f9732117000 48K r-x-- libnss_files-2.17.so 00007f9732123000 2044K ----- libnss_files-2.17.so
[root@CentOS7 proc]# cat /proc/863/maps 55ceab69c000-55ceab764000 r-xp 00000000 08:03 464614 /usr/sbin/sshd 55ceab963000-55ceab967000 r--p 000c7000 08:03 464614 /usr/sbin/sshd 55ceab967000-55ceab968000 rw-p 000cb000 08:03 464614 /usr/sbin/sshd 55ceab968000-55ceab971000 rw-p 00000000 00:00 0 55ceac9a4000-55ceac9c5000 rw-p 00000000 00:00 0 [heap] 7f9732117000-7f9732123000 r-xp 00000000 08:03 46532 /usr/lib64/libnss_files-2.17.so 7f9732123000-7f9732322000 ---p 0000c000 08:03 46532 /usr/lib64/libnss_files-2.17.so 7f9732322000-7f9732323000 r--p 0000b000 08:03 46532 /usr/lib64/libnss_files-2.17.so 7f9732323000-7f9732324000 rw-p 0000c000 08:03 46532 /usr/lib64/libnss_files-2.17.so
虚拟内存是通过CPU中的MMU(Memory Mnagement Unit)完成虚拟内存地址和物理内存地址之间的转换.程序在访问虚拟内存地址时,这个虚拟内存地址就会先发送给MMU,MMU计算出来实际的物理地址,然后再通过总线去访问实际的物理地址.
进程状态
进程的基本状态:
创建态:进程在创建时需要申请一个空白的进程控制块PCB,向其中填写空间和管理进程的信息,完成资源分配.如果创建工作无法完成.例如资源不足无法分配,卡这一步的状态就是创建态.
就绪态:进程已经准备好,就差等待CPU分配时间片的状态
在进程创建完成且已经分配好所需资源后,就会等待分配CPU的时间片的状态,
在上一个时间片内没有完成就被保存现场以后等待再次被CPU调用的的状态,
进程在运行时产生长时间的IO操作后经过等待完成IO操作等待被分配时间片时的状态
执行态:程序正在执行的状态.拥有CPU的使用权
阻塞态:正在执行的进程由于某些原因产生IO请求而暂时无法运行时,进程就收到阻塞的状态.这中状态在满足请求后就会进入就绪态.
终止态:进程结束或出现错误,或者被系统终止的状态
进程切换路径6种:
创建 to 就绪
就绪 to 执行
执行 to 就绪
执行 to 阻塞
阻塞 to 就绪
执行 to 结束
进程更多的状态介绍:
运行态:running
就绪态:reading
睡眠态:分为可中断睡眠(interruptable)和不可中断睡眠(uninterruptable)
停止态:stiopped,暂停于内存,但不会被再次被调度运行,只能手工启动
僵尸态:zombie,结束了子进程,但是父进程没有收尸,此时子进程的状态就是僵尸态
进程间通讯IPC
Inter process communication
同一主机:
管道
套接字
共享内存
信号
文件映射,将一个文件中的一段数据映射到物理内存中.
锁
信号量
不同主机:
SOCKET
RPC,remote procedure call
MQ 消息队列
进程的优先级
系统优先级:
LIUNX内核将系统优先级划分两部分:实时优先级和非实时优先级
实时优先级,0~99
非实时优先级,100~139
实时优先级是给内核使用的,
非实时优先级是给普通进程使用的
优先级中数字越小数字优先级越高
NICE优先级:
NICE优先级知识给普通进程使用的
范围是-20~19
NICE的-20对应的系统优先级是100
NICE的0对应的系统高优先级是120
NICE的19对应的系统优先级是139
TOP命令中优先级
范围是0~39
TOP中的0对应系统的优先级是100
TOP中的39对应的系统优先级是139
普通用户只能调大优先级的数字,意思就是普通用户不能提高进程的优先级
只有管理员才可以提高进程的优先级.
提到优先级就不得不提下时间复杂度了,这里引用的上头条作者的文章,我把链接放下来:https://www.toutiao.com/a6643648147614597639/,相信感谢作者
时间复杂度O(1)理解:
O(1)表示,随着计算量的增加他的时间复杂度恒定为固定值.
在linux当中一共有两组队列,一组是运行队列,一组是就绪队列.每一组队列当中又由140个子队列,每个子队列就代表着一个优先级,表示0~139个优先级.根据进程的优先级就会分布在这140个子队列中.
系统会首先判断140个队列的优先级,把0号队列的优先级上的进程从前到后先取出一个开始运行,当运行完这个进程后,就会把该进程放进就绪队列当中,然后再从运行队列中去下一个进程,运行完在放入到就绪队列.当0号运行队列中已经没有了就绪态的进程就会把,就绪队列变成运行队列.而空的原运行队列就变成就绪队列.如此往复,实现了系统检索优先级的时候只是在这280个对联中查找.所以时间复杂度是恒定的.
时间复杂度O(n)理解:
这里用使用contains()方法使用查找List集合里面的某个元素来举例。List是有序表,不能直接一次性查找到。比如从{12,23,45,··· ···,76,32}里面查找76,要从12开始查找,一次次循环查找,直到查到76并返回。这里每次的查找时间复杂度为O(1),需要查找N次才能查到76,则时间复杂度可以看作是N * O(1)=O(n)。注意,这里的n不是具体的数值N,不要以为查询了100次就是O(100),这是错的,这里只是为了方便理解(前面说了,时间复杂度并不是单指耗时,下同)。
时间复杂度O(logn)理解:
一般的查找都是O(n),但是如果通过算法,可以使查找的时间复杂度降低,比如二分查找。像上面解释O(n)的例子中,采用二分查找的话,是不是就是个log(O(n))的对数数学模型,所以其时间复杂度为O(logn)。
时间复杂度O(n^2)理解:
这里拿冒泡排序对某个数组进行有序排序举例。在冒泡排序中,分为获取值、对该值进行排序、重复取值排序三个步骤。其中取值时间复杂度为O(1),则在N个数中进行该值的比较排序,则为N*O(1)=O(n)时间复杂度。这时候还没有获取到有序数组,必须对这N个数重复进行取值、排序,执行N次,故时间复杂度为N * N * O(1)=O(n^2)。
放在最后还是那句话,作为一个初学的笔者,同学们在看笔记的时候一定要本着一个怀疑的态度来看,来思考写的对不对,只有自己确认过的才是可以相信.笔记有误支出,请见谅.