
1、冯诺依曼体系结构我们常用的计算机服务器等大部分都遵守冯诺依曼体系。关于冯诺依曼必须强调几点这里的存储器指的是内存不考虑缓存情况这里的CPU能且只能对内存进行读写不能访问外设(输入或输出设备)(数据层面)外设(输入或输出设备)要输入或者输出数据也只能写入内存或者从内存中读取。⼀句话所有设备都只能直接和内存打交道。2、操作系统任何计算机系统都包含⼀个基本的程序集合称为操作系统(OS)。笼统的理解操作系统包括内核进程管理内存管理文件管理驱动管理其他程序例如函数库shell程序等等设计OS的目的对下与硬件交互管理所有的软硬件资源对上为用户程序应用程序提供⼀个良好的执行环境3、进程进程 内核数据结构(task_struct) 自己的程序代码和数据3.1 描述进程-PCB基本概念进程信息被放在⼀个叫做进程控制块的数据结构中可以理解为进程属性的集合。课本上称之为PCBprocess control block Linux 操作系统下的 PCB 是: task_structtask_struct是PCB的⼀种在 Linux 中描述进程的结构体叫做 task_struct 。task_struct 是 Linux 内核的⼀种数据结构类型它会被装载到RAM(内存)里并且包含着进程的信息。3.2 task_ struct内容分类标示符: 描述本进程的唯⼀标示符用来区别其他进程。状态: 任务状态退出代码退出信号等。优先级: 相对于其他进程的优先级。程序计数器: 程序中即将被执行的下⼀条指令的地址。内存指针: 包括程序代码和进程相关数据的指针还有和其他进程共享的内存块的指针上下文数据: 进程执行时处理器的寄存器中的数据I ∕ O状态信息: 包括显示的I/O请求,分配给进程的I∕O设备和被进程使用的文件列表。记账信息: 可能包括处理器时间总和使用的时钟数总和时间限制记账号等。其他信息所有运行在系统里的进程都以 task_struct 双链表的形式存在内核里。3.3 查看进程进程的信息可以通过 /proc 系统文件夹查看大多数进程信息同样可以使用top和ps这些用户级⼯具来获取3.4 通过系统调用创建进程-fork初识fork有两个返回值 父子进程代码共享数据各自开辟空间私有一份采用写时拷贝1. fork 为什么会有两个返回值不是一个函数返回两次而是调用 fork 之后操作系统创建了一个新进程变成两个进程各自执行 fork 之后的代码各自拿到一份返回值。调用fork()之前只有父进程这 1 个进程在运行。调用fork()的一瞬间OS 复制父进程创建出子进程子进程几乎完整拷贝父进程的地址空间、代码、数据。fork系统调用在父进程里返回一次同时在新建出来的子进程里再返回一次。所以代码上看起来同一个fork调用出现两个返回值。本质是两个独立进程各自拿到返回值。2. 两个返回值分别给谁父进程fork返回 0 的正数这个数字就是子进程的 PID进程号。子进程fork返回0。出错情况fork 失败进程数量上限等返回-1此时不会创建子进程。3.同一个变量 ret为什么 if 和 else if 可以同时成立很多初学者会疑惑ret 一个变量怎么if(ret0)和else if(ret0)都执行真相不是同一个变量fork创建子进程时会拷贝父进程的内存子进程拥有属于自己独立的地址空间。父进程内存里的ret存的是子进程 PID正数子进程内存里的ret存的是 0两个进程两份独立的 ret 变量各自走自己的分支。父进程走else if(ret0)子进程走if(ret0)两个分支分别在两个进程里面运行互不干扰。并不是单进程里面一个变量同时等于 0 又大于 0。3.5 进程状态⼀个进程可以有几个状态在Linux内核里进程有时候也叫做任务R运行状态running: 并不意味着进程⼀定在运行中它表明进程要么是在运行中要么在运行队列里。S睡眠状态sleeping): 意味着进程在等待事件完成这里的睡眠有时候也叫做可中断睡眠interruptible sleep。D磁盘休眠状态Disk sleep有时候也叫不可中断睡眠状态uninterruptible sleep在这个状态的进程通常会等待IO的结束。T停止状态stopped 可以通过发送 SIGSTOP 信号给进程来停止T进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。X死亡状态dead这个状态只是⼀个返回状态你不会在任务列表里看到这个状态。进程状态查看ps aux / ps axj 命令a显示⼀个终端所有的进程包括其他用户的进程。x显示没有控制终端的进程例如后台运行的守护进程。j显示进程归属的进程组ID、会话ID、父进程ID以及与作业控制相关的信息u以用户为中心的格式显示进程信息提供进程的详细信息如有用户、CPU和内存使用情况等3.51 僵尸进程僵死状态Zombies是一个比较特殊的状态。当进程退出并且父进程没有读取到子进程退出的返回代码时就会产生僵死进程僵死进程会以终止状态保持在进程表中并且会⼀直在等待父进程读取退出状态代码因为需要告诉父进程任务进行得怎么样。所以只要子进程退出父进程还在运行但父进程没有读取子进程状态子进程进入Z状态僵尸进程的危害僵尸进程已释放用户态内存但内核中 task_struct 等 PCB 资源未释放会造成内核内存资源泄漏。它持续占用 PID 与内核进程表项大量堆积会耗尽 PID导致系统无法创建新进程。大量僵尸进程还会干扰进程排查掩盖系统其他异常问题。3.52 孤儿进程问题父进程如果提前退出那么子进程后退出进入Z之后那该如何处理呢父进程先退出子进程就称之为“孤儿进程”孤儿进程被1号init / systemd进程领养当然要有init / systemd进程回收模拟孤儿进程3.6 进程优先级cpu资源分配的先后顺序就是指进程的优先权priority。优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用可以改善系统性能。还可以把进程运行到指定的CPU上这样⼀来把不重要的进程安排到某个CPU可以改善系统整体性能。3.61 查看系统进程在linux或者unix系统中用ps ‒l命令则会类似输出以下几个内容我们很容易注意到其中的几个重要信息有下UID : 代表执行者的身份PID : 代表这个进程的代号PPID 代表这个进程是由哪个进程发展衍生而来的亦即父进程的代号PRI 代表这个进程可被执行的优先级其值越小越早被执行NI 代表这个进程的nice值3.62 PRI and NIPRI也还是比较好理解的即进程的优先级或者通俗点说就是程序被CPU执行的先后顺序此值越小进程的优先级别越高那NI呢?就是我们所要说的nice值了其表示进程可被执行的优先级的修正数值PRI值越小越快被执行那么加入nice值后将会使得PRI变为PRI(new)PRI(old)nice这样当nice值为负值的时候那么该程序将会优先级值将变小即其优先级会变高则其越快被执行所以调整进程优先级在Linux下就是调整进程nice值nice其取值范围是-20至19⼀共40个级别。3.63 PRI vs NI需要强调⼀点的是进程的nice值不是进程的优先级他们不是⼀个概念但是进程nice值会影响到进程的优先级变化。可以理解nice值是进程优先级的修正数据3.64 查看进程优先级的命令⽤top命令更改已存在进程的nicetop进入top后按“r”‒输入进程PID‒输入nice值3.7 进程切换CPU上下文切换其实际含义是任务切换, 或者CPU寄存器切换。当多任务内核决定运行另外的任务时, 它保存正在运行任务的当前状态, 也就是CPU寄存器中的全部内容。这些内容被保存在任务自己的堆栈中, 入栈工作作完成后就把下⼀个将要运行的任务的当前状况从该任务的栈中重新装入CPU寄存器,并开始下⼀个任务的运行, 这⼀过程就是context switch。每个进程都会分配对应的时间片如果没在时间片指定的时间内完成任务该进程会被暂时切下来需要进程自己保存自己得上下文数据目的是下次回来能够恢复按照之前得逻辑向后运行。3.8 Linux内核进程O(1)调度队列时间片还没有结束的所有进程都按照优先级放在该队列nr_active: 总共有多少个运行状态的进程queue[140]: ⼀个元素就是⼀个进程队列相同优先级的进程按照FIFO规则进行排队调度,所以数组下标就是优先级从该结构中选择⼀个最合适的进程过程是怎么的呢从0下表开始遍历queue[140]找到第⼀个非空队列该队列必定为优先级最高的队列拿到选中队列的第⼀个进程开始运行调度完成遍历queue[140]时间复杂度是常数bitmap[5]:⼀共140个优先级⼀共140个进程队列为了提高查找非空队列的效率就可以用5*32个比特位表示队列是否为空3.81 过期队列过期队列和活动队列结构⼀模⼀样过期队列上放置的进程都是时间片耗尽的进程当活动队列上的进程都被处理完毕之后对过期队列的进程进行时间片重新计算3.82 active指针和expired指针active指针永远指向活动队列expired指针永远指向过期队列可是活动队列上的进程会越来越少过期队列上的进程会越来越多因为进程时间片到期时⼀直都存在的。新加进来的进程也会放在过期队列里面相当于进程状态中的就绪状态只要能够交换active指针和expired指针的内容就相当于有具有了⼀批新的活动进程4、调度算法为o(1)原因从 active 选最高优先级进程运行进程时间片用完把它挪到 expired 队列active 全部空了的时候直接交换 active 和 expired 指针不需要移动任何进程只是交换两个指针变量常数操作。