什么是操作系统
- 我们可以把它看成应用程序和硬件之间插入的一层软件,所有应用程序对硬件的操作必须通过操作系统。防止硬件被程序滥用 以及 向应用程序提供简单一致的接口来访问硬件 是操作系统的两大基本功能。
- 具体来说 操作系统应该包括 内核、设备驱动程序、启动引导程序、命令行shell或其他种类的用户界面、基本的文件管理工具和系统工具等部分。
其中内核通常由 负责响应中断的中断服务程序、负责管理多个进程的调度程序、负责管理进程地址空间的内存管理程序、和进程间通信等系统服务程序组成。进而提供了管理硬件设备、分配系统资源、管理应用程序的服务,是操作系统核心。
进程管理
百度百科 🔗
在现代操作系统中,进程提供两种虚拟机制:虚拟处理器和虚拟内存。
进程线程的区别
- 先说下什么是进程,线程的引入和线程。
- 进程:是操作系统对一个正在运行的程序的抽象概念,是处于执行器的程序以及相关资源的总称。不仅包含可执行程序代码,通常还好包含打开的文件、挂起的信号、内核内部数据结构、处理器状态、具有内存映射的地址空间以及多个执行线程等。
- 多进程:早期由于 CPU高速和IO低速的矛盾引入多道批处理程序,而程序在执行过程中因为共享资源导致在执行过程中相互限制,所以引入进程给程序提供一个抽象的概念,它能申请系统资源并提供给程序使用。在多处理器多核cpu系统上多进程的引入更是必然。
- 多线程:因为多线程之间比多进程之间更容易共享数据,调度时切换开销也比较小。进程粒度太大了,为了提高cpu利用率开启多进程,可能大部分时间都用于进程切换,引入线程机制也是有必要的。
- 不同系统实现线程的机制不一样。像Windos在内核中提供了专门支持线程的机制,这种系统通常把线程称作轻量级线程,线程被抽象成一种耗费较少资源,运行匀速的执行单元。而对于Linux来说,线程机制只是一种进程间共享资源的手段。
举例来说:在提供专门线程支持的系统中,通常会有一个包含指向四个线程的指针的进程描述符,线程本身去描述它独占的资源。相反,Linux仅仅创建四个进程并分配四个普通的task_struct结构,建立时指定他们共享某些资源。
- 所以说 进程和线程都是一个概念,都是对运行的程序的描述的抽象概念。在专门支持线程机制的系统中,线程运行在进程上下文中更轻量,开销更小罢了。
尤其是在Linux中,线程和进程几乎没有区别,也是通过系统调用clone()创建的,不过需要传递一些参数标志需要共享的资源。
进程上下文包含哪些部分
借鉴
处理器总处于以下三种状态之一:
- 内核态,运行于进程上下文,内核代表进程运行于内核空间;
- 内核态,运行于中断上下文,内核代表硬件运行于内核空间;
- 用户态,运行于用户空间。
进程上下文包含三部分:
- 用户级上下文: 代码、数据、用户堆栈以及具有内存映射的地址空间。
- 寄存器上下文: 通用寄存器、程序寄存器(IP)、处理器状态寄存器(EFLAGS)、栈指针(ESP)。
- 系统级上下文: 进程控制块task_struct、内存管理信息(mm_struct、vm_area_struct、pgd、pte)、内核栈。
中断上下文:硬件通过触发信号,导致内核调用中断处理程序,进入内核空间。这个过程中,硬件的 一些变量和参数也要传递给内核,内核通过这些参数进行中断处理。所谓的“ 中断上下文”,其实也可以看作就是硬件传递过来的这些参数和内核需要保存的一些其他环境(主要是当前被打断执行的进程环境)。
当发生进程调度时,进行进程切换就是上下文切换(context switch).操作系统必须对上面提到的全部信息进行切换,新调度的进程才能运行。而系统调用进行的模式切换(mode switch)。模式切换与进程切换比较起来,容易很多,而且节省时间,因为模式切换最主要的任务只是切换进程寄存器上下文的切换。
进程切换和线程切换的区别,为什么线程切换开销更小?
fork exit
进程状态 僵尸进程 孤儿进程 后台进程
僵尸进程:
- 定义:
当子进程比父进程先结束,而父进程又没有回收子进程,释放子进程的资源。此时子进程成为一个僵尸进程。白话就是:子进程比父进程先结束,在每个进程退出的时候,内核释放该进程所有的资源,包括打开的文件,占用的内存等。但是仍然为其保留一定的信息(包括进程号the process ID,退出状态the termination status of the process,运行时间the amount of CPU time taken by the process等),子进程调用exit之后还会占用内存(内核栈、thread_info、task_struct) 并没有真正的被销毁。而父进程比子进程结束的晚,且父进程没有wait()或waitpid()子进程、父进程没有对于SIGCHLD信号的handler、父进程没有忽略SIGCHLD信号,在父进程没有结束之前,子进程都是僵尸进程。 - 避免:
- 父进程通过wait和waitpid等函数等待子进程结束,这会导致父进程挂起。
- 可以通过signal函数为SIGCHLD安装handler,因为子进程结束后, 父进程会收到该信号,可以在handler中调用wait回收。
- 如果父进程不关心子进程什么时候结束,那么可以用signal(SIGCHLD,SIG_IGN) 通知内核,自己对子进程的结束不感兴趣,那么子进程结束后,内核会回收, 并不再给父进程发送信号。(注意忽略信号这部代码的执行应该放在子进程结束之前执行,所以一般放在fork前)
- 如何查找僵尸进程并杀死:ps axu
-
VSZ:进程占用虚拟内存大小
-
STAT:进程状态 状态后缀:
<:优先级高的进程
N:优先级低的进程
L:有些页被锁进内存
s:进程的领导者(在它之下有子进程)(也就是说包含子线程)
l:ismulti-threaded (using CLONE_THREAD, like NPTL pthreads do)多线程
+:位于后台的进程组 -
TIME:进程消耗CPU时间
-
COMMAND:执行指令的名称和参数
杀死僵尸进程:
killall kill -15 kill -9 一般都不能杀掉 defunct进程
用了kill -15,kill -9以后 之后反而会多出更多的僵尸进程
kill -kill pid fuser -k pid 可以考虑杀死他的parent process,
kill -9 他的parent process
- 僵尸进程危害:系统所能使用的进程号是有限的,如果大量的产生僵尸进程,将因为没有可用的进程号而导致系统不能产生新的进程