20、Linux 操作系统的核心是什么?
Linux 操作系统的核心是内核 Kernel
21、什么是 Linux 内核?
内核是 Linux 操作系统的关键组件,它借助进程间的通信和系统调用,管理着系统上的所有软硬件,充当软件和硬件之间的桥梁角色
内核的任务:
- 应用程序执行的流程管理
- 内存和 I/O 管理
- 系统调用的控制
- 通过设备驱动程序来管理设备
总结:内核是硬件与软件之间的一个中间层,当软件(应用程序)需要去操作底层硬件时,需要通过内核来实现。例如你想播放一首歌曲,则播放程序就会去向内核发起请求,内核则会去调用音箱播放歌曲(对于应用程序来说它是不知道底层硬件的,它的认知最底层就是内核)
22、Linux 进程三大基本状态是什么?
就绪态
- 进程已经分配到除了 CPU 以外的所有资源,只需要获得 CPU 便可立即执行
- 即:万事俱备只欠 CPU
执行态
- 进程已经获得 CPU ,正在 CPU 上执行
阻塞态
- 正在执行的进程,由于要等待某个事件发生(例如等待 I/O 完成、等待信号、等待数据)而无法继续执行时,就会放弃 CPU 进入到阻塞态
PS:进程三种状态的切换
- 就绪态——>执行态
处于就绪态的进程,当进程调度程序为其分配了一个CPU后,该进程便由就绪态转为执行态
- 执行态——>就绪态
处于执行状态的进程在执行过程中,因分配的时间片用完而不得已让出 CPU,便由执行态转
变成就绪态
- 执行态——>阻塞态
处在执行态的进程因等待某个事情发生而无法继续执行时,便由执行态转变成阻塞态
- 阻塞态——>就绪态
处于阻塞态的进程,如果等待的事件已经发生,便由阻塞态转变成就绪态
23、如何将文本中的注释和空行过滤掉?
grep -Ev "^#|^$" file
^#:以#开头,即注释
^$:空行
24、如何知道是哪个进程打开了哪个文件
通过 lsof 命令,在 Linux 中一切皆文件,通过 lsof 命令我们可以知道所有被进程打开的文件
举个例子:有一个文件一直被某个进程打开写入导致你删除不了这个文件,你就可以使用 lsof 命令找到是哪个进程占用文件,再将进程 kill 掉就能删掉文件了
25、父子进程之间怎么通信?
管道
- 普通管道(pipe)
- 流管道(s_pipe)
- 命名管道(FIFO)
- 共享内存:共享内存允许两个不相关的进程访问同一个逻辑内存
- 消息队列
26、什么是僵尸进程?什么是孤儿进程?
僵尸进程:
当子进程比父进程先结束,而父进程又没有回收子进程、释放子进程占用的资源,此时子进程就会变成僵尸进程
即僵尸进程是一个早已死亡的进程,但在进程表中仍占据一个位置
孤儿进程:
如果父进程先结束,子进程就会变成孤儿进程,会被 init 进程接管,子进程结束后其占用资源就会被 init 进程回收
为了避免孤儿进程退出时所占资源无法被回收而变成僵尸进程,init 进程会接管这些孤儿进程,被Init接管的所有进程都不会变成僵尸进程
27、如何查看文件的访问时间、修改时间?
使用 stat 命令,可以查看到文件的详细信息
28、在不查看文件内容的情况下,如何快速判断这两份文件内容是否相同
使用 md5sum——计算检验 MD5 校验码
md5sum命令采用MD5报文摘要算法(128位)计算和检查文件的校验和
有 A.txt 和 B.txt 两份文件,可以通过 MD5sum A.txt B.txt 命令来比较这两个文件内容是否相同
29、哪个配置文件可以设置 DNS server?
/etc/reslove.conf
30、任务计划格式中,前面5个数字分表表示什么含义?
分时日月周
31、什么是系统负载?
系统负载表示处在可执行状态和不可中断睡眠状态的进程数量
可执行状态进程:
- 指的是正在被CPU执行的进程以及在就绪队列上等待被CPU执行的进程(运行态、就绪态)
不可中断睡眠状态进程:
- 指的是处于内核关键流程中的进程,而且这些流程不可以被打断(阻塞态)
32、什么是 CPU 使用率?
CPU使用率是指在单位时间内CPU处在非空闲态的时间比,反映了CPU的繁忙程度
比如说:比如说单核CPU一秒内处在非空闲态的时间为0.6秒,那么它的CPU使用率就是60%
而双核CPU一秒内处在非空闲态的时间分别为0.6s和0.4s,那么它的CPU使用率为(0.4+0.6)/ 2 * 100% = 50%
举个例子:
比如说有一家银行,只有一个业务窗口,每次只能接待一个人(单核CPU)
这一天,有五个人要来办理业务,由于只有一个窗口,就会出现一人办理另外四人等待的情况(平负载为5)
在业务窗口那个人只有真正办理业务才算是真正使用这个窗口,才意味着窗口正在忙碌(CPU使用率)
33、CPU 使用率与系统负载的关系
总结:
- cpu使用率升高,会导致平均负载升高
- 平均负载升高,CPU使用率不一定会升高(有可能是I/O压力使得出现大量不可中断睡眠进程导致的平均负载升高,但这是 CPU 是空闲状态的)
34、什么是 CPU 上下文切换?
先来了解下什么是 CPU 上下文
Linux是一个多任务操作系统,它支持远大于CPU数量的任务同时运行,但这些任务并不是真正在同时运行,而是系统在很短时间内将CPU轮流分配给它们,造成了多任务同时进行的错觉(宏观上并发)
比如说B任务在就绪队列等待CPU执行完A任务后执行它,那么CPU就需要知道任务从哪里加载,从哪里开始执行,这些都是系统事先帮它设置好CPU寄存器和程序计数器,即 CPU 上下文
CPU上下文切换
CPU上下文切换就是先把前一个任务(A任务)的CPU上下文(也就是 CPU 寄存器和程序计数器)保存起来然后加载新任务(B任务)的上下文到CPU寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务而保存起来的上下文,会存储在系统内核中,当该任务重新调度执行时会再次加载进来,从而保证任务原来状态不受影响
35、进程如何访问计算机内存?
进程是无法之间访问物理内存的,只有内核才可以访问物理内存
Linux 内核给每个进程都提供了一个独立的连续的虚拟地址空间,通过这个空间进程就可以访问到虚拟内存,而这个虚拟地址空间又被分为内核空间和用户空间
进程在用户态时能访问用户地址空间,在内核态可以访问内核地址空间
每个进程的内核空间内存关联的都是相同的物理内存,方便进程切换到内核态后访问
不是所有的虚拟内存都会被分配到物理内存的,只有那些实际使用的虚拟内存才被分配物理内存,并且通过内存映射来管理
内存映射:虚拟内存地址映射到物理内存地址为了完成内存映射,内核为每个进程都维护了一张页表,记录虚拟地址与物理地址的映射关系
36、聊聊 Linux 的写时复制吧
先来看下 Linux 的两个函数——fork() 和 exec()
fork()
- Linux 系统中创建进程的主要方法,通过 fork() 会创建出一个和父进程完全相同的子进程
- Linux下 init 进程是所有进程的爹,Linux 的进程都通过 init 进程或 init 的子进程fork(vfork) 出来的
exec()
- 父进程 fork 出一个子进程,这个子进程是父进程的副本
- exec() 作用就是装载一个新的程序(可执行映像),覆盖当前进程内存空间中的映像,从而执行不同的任务
- 即 exec() 在执行时会直接替换掉当前进程的地址空间
了解了这两个函数的作用后,再来看下写时复制技术
Linux 写时复制技术(copy-on-write),简称 COW
传统做法下,父进程 fork 出一个和它完全相同的子进程,会直接将父进程的数据拷贝到子进程中,父子进程之间的数据段和堆栈是相互独立的
一般来说,子进程被 fork 出之后都会执行 exec() 来实现自己想要的功能
所以如果按照传统的做法,父进程 fork 子进程时拷贝过去的数据是没用的,因为子进程会执行 exec() ,导致原数据被清空
既然很多时候父进程拷贝给子进程的数据是无效的,于是便有了写时复制这项技术
COW介绍:
- 父进程 fork 出的子进程与父进程共享内存空间,即一开始的时候父进程的数据不会复制给子进程,这样创建子进程的速度就很快了!(不用复制,直接指向父进程的物理空间)
- 只有当父子进程中有更改段的事件发生时(即写入操作),再为子进程分配相应的物理空间
COW原理:
- fork之后,内核把父进程中所有的内存页的权限设置为只读,然后子进程的地址空间指向父进程,与父进程共享数据。当父子进程都只读内存时,正常执行
- 当其中某个进程写内存时,CPU 检测到内存页是只读的,就会触发页异常中断,这时候内核就会把触发异常的页复制一份出来,这样父子进程就各自持有独立的异常页(其余的页还是共享父进程的)
COW好处:
- 减少分配和复制大量资源时带来的时间消耗
- 检查不必要的资源分配,比如fork进程时,并不是所有的页面都需要复制,父进程的代码段和只读数据段都不被允许修改,所以无需复制
PS:除了 fork() 之外其实有个 vfork()
这个 vfork() 更牛掰,内核连子进程的虚拟地址空间结构也不创建了,直接共享父进程的虚拟空间,也意味着共享了父进程的物理空间
总结:写时复制,即资源的复制只有在需要写入的时候才进行,不然就是以只读的形式共享,这样可以省去了 fork 子进程时的无用数据复制所需的开销
37、程序和进程的区别
我们知道,计算机只认识 0 和 1,所以无论用哪种语言编写代码,最后都需要通过某种方法将其翻译成二进制文件,才能在计算机中运行起来
而为了让这些代码能够正常运行,我们往往还要给它提供数据,这些数据加上代码本身的二进制文件存放在磁盘上,就是我们平常所说的一个个”程序“
然后我们就可以在计算机上运行这个程序了
首先操作系统将这个程序从磁盘读到内存当中,然后去交给 CPU 去执行,CPU 与 内存协作,又会使用到 CPU 寄存器存放数值,内存堆栈保存执行的命令和变量,如果有输入和输出,I/O 设备也会去执行
一旦程序被执行起来,它就从磁盘上的二进制文件,变成了内存中的数据、寄存器里的值,堆栈中的指令,被打开的文件,以及各种设备状态信息的一个集合,由静态变成了动态
像这样一个程序运行起来后的计算机执行环境的总和,就是我们今天的主角:进程
总结:程序是存储在磁盘上的二进制文件,进程是程序的运行时