面经:Linux&操作系统

一. linux常用命令

1. 命令汇总

cat filename 一次显示整个文件  *
cat > filename 从键盘创建一个文件
cat file1 file2 > file  将几个文件合并为一个文件
chmod  用于改变 linux 系统文件或目录的访问权限
chown 指定文件的拥有者改为指定的用户或组
cp 将源文件复制至目标文件,或将多个源文件复制至目标目录
find  在文件树中查找文件  *
locate 搜寻系统内建文档数据库达到快速找到档案 *
head -n<> -c<> 显示档案的开头至标准输出中,控制行数 *
more 分页显示 
less 随意浏览文件
ln 建立连接
mv test.log test1.txt   重命名 *
mv llog1.txt log2.txt log3.txt /test3 移动文件
rm 删除一个目录中的一个或多个文件或目录
tail  显示指定文件末尾内容 *
touch 用于修改文件或者目录的时间属性。若文件不存在,系统会建立一个新的文件。
vim  文本编辑器
whereis 用于程序名的搜索 * 
which  查看可执行文件的位置 *
wc 统计指定的文件中字节数、字数、行数 *
df 显示磁盘空间使用情况 *
du 对文件和目录磁盘使用的空间的查看 *
free  显示系统内存使用情况 *
cd 切换当前目录
 ls  查看 linux 文件夹包含的文件
 mkdir 创建文件夹
 pwd 查看当前工作目录路径
 rmdir 从一个目录中删除一个或多个子目录项 
ifconfig 查看和配置 Linux 系统的网络接口  *
iptables 配置 Linux 内核防火墙的命令行工具 *
netstat 用于显示网络状态
ping 检测主机
telnet 远端登入 *
date 显示或设定系统的日期与时间
ps 查看当前运行的进程状态
rpm 用于管理套件
top 显示当前系统正在执行的进程的相关信息,包括进程 ID、内存占用率、CPU 占用率等常用参数
yum 查找、安装、删除某一个、一组甚至全部软件包的命令
gzip,bzip2 创建 *.xx压缩文件
tar 用来压缩和解压文件
unzip 解压*.zip文件
grep命令 是查找, 是一种强大的文本搜索工具,它能 使用正则表达式 搜索文本,并把匹 配的行打印出来。 

2. 高频考题

查看当前进程:ps
查看当前路径: pwd
显示文件或目录: ls -l(列出详细信息) -a(列出所有,包括隐藏文件)
查看文件内容:cat
分页查看文件内容:more less
查看CPU状态: top
查看和配置 Linux 系统的网络接口
查看java进程:ps -ef | grep java

3. less,more,cat区别

  • cat是一次性显示整个文件的内容,还可以将多个文件连接起来显示,它常与重定向符号配合使用,适用于文件内容少的情况;
  • more和less一般用于显示文件内容超过一屏的内容,并且提供翻页的功能。
  • more比cat强大,提供分页显示的功能,less比more更强大,提供翻页,跳转,查找等命令。
  • 而且more和less都支持:用空格显示下一页,按键b显示上一页。

4. 查找文件

1   which 查看可执行文件的位置。
2   whereis 查看文件的位置。
3   locate 配合数据库查看文件位置。
4   find 实际搜寻硬盘查询文件名称。

二. 进程 线程 协程

1. 基本定义

  • 进程
    进程是系统进行资源分配和调度的一个独立单位,是系统中的并发执行的单位。
  • 线程
    线程是进程的一个实体,也是 CPU 调度和分派的基本单位,它是比进程更小的能独立运行的基本单位,有时又被称为轻权进程或轻量级进程
  • 协程
    是一种比线程更加轻量级的存在,协程不是被操作系统内核所管理,而完全是由程序所控制
    在这里插入图片描述

2. 多进程 多线程

添加链接描述
总结一下,计算密集型,适用多进程;非计算密集型(例如IO密集型,读写文件,爬虫也算),适用多线程
①一座工厂(类似CPU),假设电力有限,只能供一个车间,即只能运行一个任务,里面有许多的车间(类似进程),执行单个的任务,这时,就是每次只能单个车间运行,若是另一个车间想工作,则当前车间得休息。
②而多核CPU,就像多个工厂,它可以同时让多个车间(类似多个进程)一起工作,当然,是工作在不同工厂里,也就是运行在不同CPU核上。
③而每个车间里有很多的工人,这就类似是线程,一个车间可以有多个工人,也就是一个进程可有多个线程。

3. 并发 并行

在这里插入图片描述

三. 零拷贝

0. 面试精简版

  • 零拷贝是指计算机执行IO操作时,CPU不需要将数据从一个存储区域复制到另一个存储区域,从而可以减少上下文切换以及CPU的拷贝时间。它是一种I/O操作优化技术。
  • 传统IO的读写流程,包括了4次上下文切换(4次用户态和内核态的切换),4次数据拷贝(两次CPU拷贝以及两次的DMA拷贝)。
  • 零拷贝并不是没有拷贝数据,而是减少用户态/内核态的切换次数以及CPU拷贝的次数。零拷贝一般有这三种实现方式: mmap+write,sendfile 带有DMA收集拷贝功能的sendfile

1. DMA(直接内存访问)技术 **

  • 没有DMA时,I/O 的过程

在这里插入图片描述

  • 使用了DMA技术
    在这里插入图片描述
  • 定义
    在进行 I/O 设备和内存的数据传输的时候,数据搬运的工作全部交给 DMA 控制器,而 CPU 不再参与任何与数据搬运相关的事情,这样 CPU 就可以去处理别的事务。

2. 传统的文件传输

在这里插入图片描述

  • 四次用户态与内核态的上下文切换
    因为发生了两次系统调用,一次是 read() ,一次是 write(),每次系统调用都得先从用户态切换到内核态,等内核完成任务后,再从内核态切换回用户态。
  • 四次数据拷贝
    两次是 DMA 的拷贝,另外两次则是通过 CPU 拷贝的

    要想提高文件传输的性能,就需要减少「用户态与内核态的上下文切换」和「内存拷贝」的次数。

3. 如何优化文件传输性能

要想减少上下文切换到次数,就要减少系统调用的次数。 用户的缓冲区是没有必要存在的。

在这里插入图片描述

4. 如何实现零拷贝?

  • 方式一: mmap + write
buf = mmap(file, len);
write(sockfd, buf, len);
mmap() 系统调用函数会直接把内核缓冲区里的数据「映射」到用户空间,这样,操作系统内核与用户空间就不需要再进行任何的数据拷贝操作。

在这里插入图片描述
三次数据拷贝,四次上下文切换

  • 方式二:sendfile
    以linux内核2.4版本为例子,2.1(没有这么完善),2.4支持网卡支持SG-DMA技术
    在这里插入图片描述
  • 总结
    零拷贝(Zero-copy)技术,因为我们没有在内存层面去拷贝数据,也就是说全程没有通过 CPU 来搬运数据,所有的数据都是通过 DMA 来进行传输的。
    零拷贝技术的文件传输方式相比传统文件传输的方式,减少了 2 次上下文切换和数据拷贝次数,只需要 2 次上下文切换和数据拷贝次数,就可以完成文件的传输,而且 2 次的数据拷贝过程,都不需要通过 CPU,2 次都是由 DMA 来搬运。

5. 使用零拷贝的项目

Kafka ,Nginx

6. PageCache(磁盘高速缓存)

  • 优点弊端
    读写磁盘相比读写内存的速度慢太多了,所以我们应该想办法把「读写磁盘」替换成「读写内存」。于是,我们会通过 DMA 把磁盘里的数据搬运到内存里,这样就可以用读内存替换读磁盘。
    但是,内存空间远比磁盘要小,内存注定只能拷贝磁盘里的一小部分数据
    读写速度快 但内存小
  • 两大功能
    缓存最近被访问的数据; (LRU算法)
    预读功能;
  • 对于大文件的处理
    另外,当传输大文件时,不能使用零拷贝,因为可能由于 PageCache 被大文件占据,而导致「热点」小文件无法利用到 PageCache,并且大文件的缓存命中率不高,这时就需要使用异步 IO + 直接 IO 的方式。

    sendfile 系统调用实现了零拷贝技术,零拷贝技术的文件传输方式相比传统文件传输的方式,减少了 2 次上下文切换和数据拷贝次数,只需要 2 次上下文切换和数据拷贝次数,就可以完成文件的传输,而且 2 次的数据拷贝过程,都不需要通过 CPU,2 次都是由 DMA 来搬运,使用零拷贝的项目有nginx、kafka。

四. IO多路复用:epoll poll select

1. 基于TCP的Socket编程

在这里插入图片描述

  • 服务端:socket()函数 创建网络协议为 IPv4,以及传输协议为 TCP 的 Socket
  • 服务端: bind()函数 给这个 Socket 绑定一个 IP 地址(找网卡)和端口(找应用程序)
  • 服务端:listen()函数:监听
  • 服务端: accept() 函数 从内核获取客户端的连接,如果没有客户端连接,则会阻塞等待客户端连接的到来
  • 客户端: connect() 函数发起连接,该函数的参数要指明服务端的 IP 地址和端口号,然后万众期待的 TCP 三次握手就开始了
  • 当 TCP 全连接队列不为空后,服务端的 accept() 函数,就会从内核中的 TCP 全连接队列里拿出一个已经完成连接的 Socket 返回应用程序,后续数据传输都用这个 Socket。
    在这里插入图片描述

2.多进程模型

在这里插入图片描述
服务器的主进程负责监听客户的连接,一旦与客户端连接完成,accept() 函数就会返回一个「已连接 Socket」,这时就通过 fork() 函数创建一个子进程,实际上就把父进程所有相关的东西都复制一份,包括文件描述符、内存地址空间、程序计数器、执行的代码等。

  • 存在的问题:僵尸进程
    当「子进程」退出时,实际上内核里还会保留该进程的一些信息,也是会占用内存的,如果不做好“回收”工作,就会变成僵尸进程,随着僵尸进程越多,会慢慢耗尽我们的系统资源。父进程要“善后”好自己的孩子,怎么善后呢?那么有两种方式可以在子进程退出后回收资源,分别是调用 wait() 和 waitpid() 函数。

3. 多线程模型

在这里插入图片描述
当服务器与客户端 TCP 完成连接后,通过 pthread_create() 函数创建线程,然后将「已连接 Socket」的文件描述符传递给线程函数,接着在线程里和客户端进行通信,从而达到并发处理的目的。并且使用线程池的方式来避免线程的频繁创建和销毁。

4. I/O多路复用

只使用一个进程来维护多个 Socket
在这里插入图片描述
一个进程虽然任一时刻只能处理一个请求,但是处理每个请求的事件时,耗时控制在 1 毫秒以内,这样 1 秒内就可以处理上千个请求,把时间拉长来看,多个请求复用了一个进程,这就是多路复用
select/poll/epoll 内核提供给用户态的多路复用系统调用,进程可以通过一个系统调用函数从内核中获取多个事件
select/poll/epoll 是如何获取网络事件的呢?在获取事件时,先把所有连接(文件描述符)传给内核,再由内核返回产生了事件的连接,然后在用户态中再处理这些连接对应的请求即可

5. select/poll

  • select实现多路复用的方式
    将已连接的 Socket 都放到一个文件描述符集合,然后调用 select 函数将文件描述符集合拷贝到内核里,让内核来检查是否有网络事件产生,检查的方式很粗暴,就是通过遍历文件描述符集合的方式,当检查到有事件产生后,将此 Socket 标记为可读或可写, 接着再把整个文件描述符集合拷贝回用户态里,然后用户态还需要再通过遍历的方法找到可读或可写的 Socket,然后再对其处理。
    2 次「遍历」文件描述符集合
    2 次「拷贝」文件描述符集合

  • select与poll对比

  • 区别:用来表示文件描述符集合的数据结构
    select 使用固定长度的 BitsMap,表示文件描述符集合
    poll 用动态数组,以链表形式来组织,突破了 select 的文件描述符个数限制,当然还会受到系统文件描述符限制。

  • 相同
    都是使用「线性结构」存储进程关注的 Socket 集合,因此都需要遍历文件描述符集合来找到可读或可写的 Socket,时间复杂度为 O(n),而且也需要在用户态与内核态之间拷贝文件描述符集合,这种方式随着并发数上来,性能的损耗会呈指数级增长

6. epoll

6.1 基本定义用法

int s = socket(AF_INET, SOCK_STREAM, 0);
bind(s, ...);
listen(s, ...)

int epfd = epoll_create(...);
epoll_ctl(epfd, ...); //将所有需要监听的socket添加到epfd中

while(1) {
    int n = epoll_wait(...);
    for(接收到数据的socket){
        //处理
    }
}

在这里插入图片描述

  • 对select和poll的改进
  • epoll 在内核里使用红黑树来跟踪进程所有待检测的文件描述字,把需要监控的 socket 通过 epoll_ctl() 函数加入内核中的红黑树里,红黑树是个高效的数据结构,增删改一般时间复杂度是 O(logn)。
  • epoll 使用事件驱动的机制,内核里维护了一个链表来记录就绪事件,当某个 socket 有事件发生时,通过回调函数内核会将其加入到这个就绪事件列表中,当用户调用 epoll_wait() 函数时,只会返回有事件发生的文件描述符的个数,不需要像 select/poll 那样轮询扫描整个 socket 集合,大大提高了检测的效率。

6.2 边缘触发和水平触发

epoll 支持两种事件触发模式,分别是边缘触发(edge-triggered,ET)和水平触发(level-triggered,LT)。

  • 边缘触发
    使用边缘触发模式时,当被监控的 Socket 描述符上有可读事件发生时,服务器端只会从 epoll_wait 中苏醒一次,即使进程没有调用 read 函数从内核读取数据,也依然只苏醒一次,因此我们程序要保证一次性将内核缓冲区的数据读取完;
  • 水平触发
    使用水平触发模式时,当被监控的 Socket 上有可读事件发生时,服务器端不断地从 epoll_wait 中苏醒,直到内核缓冲区数据被 read 函数读完才结束,目的是告诉我们有数据需要读取;
    在这里插入图片描述

五. 进程间的通信方式

1. 管道

  • 引入
$ ps auxf | grep mysql

上面命令行里的「|」竖线就是一个管道,它的功能是将前一个命令(ps auxf)的输出,作为后一个命令(grep mysql)的输入,从这功能描述,可以看出管道传输数据是单向的,如果想相互通信,我们需要创建两个管道才行。
管道这种通信方式效率低,不适合进程间频繁地交换数据

  • 管道基本原理

在这里插入图片描述
所谓的管道,就是内核里面的一串缓存。从管道的一段写入的数据,实际上是缓存在内核中的,另一端读取,也就是从内核中读取这段数据。另外,管道传输的数据是无格式的流且大小受限。

  • 父子进程管道
    在这里插入图片描述
    使用 fork 创建子进程,创建的子进程会复制父进程的文件描述符,这样就做到了两个进程各有两个「 fd[0] 与 fd[1]」,两个进程就可以通过各自的 fd 写入和读取同一个管道文件实现跨进程通信了。
    在这里插入图片描述
    管道只能一端写入,另一端读出,父进程关闭读取的 fd[0],只保留写入的 fd[1];子进程关闭写入的 fd[1],只保留读取的 fd[0];
    在这里插入图片描述
  • 匿名管道与命名管道

匿名管道顾名思义,它没有名字标识,匿名管道是特殊文件只存在于内存,没有存在于文件系统中,shell 命令中的「|」竖线就是匿名管道,通信的数据是无格式的流并且大小受限,通信的方式是单向的,数据只能在一个方向上流动,如果要双向通信,需要创建两个管道,再来匿名管道是只能用于存在父子关系的进程间通信匿名管道的生命周期随着进程创建而建立,随着进程终止而消失。

命名管道FIFO突破了匿名管道只能在亲缘关系进程间的通信限制,因为使用命名管道的前提,需要在文件系统创建一个类型为 p 的设备文件,那么毫无关系的进程就可以通过这个设备文件进行通信。另外,不管是匿名管道还是命名管道,进程写入的数据都是缓存在内核中,另一个进程读取数据时候自然也是从内核中获取,同时通信数据都遵循先进先出原则,不支持 lseek 之类的文件定位操作。

2. 消息队列

消息队列克服了管道通信的数据是无格式的字节流的问题,消息队列实际上是保存在内核的「消息链表」,消息队列的消息体是可以用户自定义的数据类型,发送数据时,会被分成一个一个独立的消息体,当然接收数据时,也要与发送方发送的消息体的数据类型保持一致,这样才能保证读取的数据是正确的。消息队列通信的速度不是最及时的,毕竟每次数据的写入和读取都需要经过用户态与内核态之间的拷贝过程。

3. 共享内存

在这里插入图片描述
共享内存可以解决消息队列通信中用户态与内核态之间数据拷贝过程带来的开销,它直接分配一个共享空间,每个进程都可以直接访问
带来新的问题,多进程竞争同个共享资源会造成数据的错乱

4. 信号量

为了防止多进程竞争共享资源,而造成的数据错乱,所以需要保护机制使得共享的资源,在任意时刻只能被一个进程访问。正好,信号量就实现了这一保护机制。

信号量其实是一个整型的计数器,主要用于实现进程间的互斥与同步,而不是用于缓存进程间通信的数据。
在这里插入图片描述

  • 一个是 P 操作,这个操作会把信号量减去 1,相减后如果信号量 < 0,则表明资源已被占用,进程需阻塞等待;相减后如果信号量 >=
    0,则表明还有资源可使用,进程可正常继续执行。
  • 另一个是 V 操作,这个操作会把信号量加上 1,相加后如果信号量 <=
    0,则表明当前有阻塞中的进程,于是会将该进程唤醒运行;相加后如果信号量 > 0,则表明当前没有阻塞中的进程;
  • 信号初始化为 1,就代表着是互斥信号量,它可以保证共享内存在任何时刻只有一个进程在访问,这就很好的保护了共享内存。
  • 信号初始化为 0,就代表着是同步信号量,它可以保证进程 A 应在进程 B 之前执行

5. 信号

上面说的进程间通信,都是常规状态下的工作模式。对于异常情况下的工作模式,就需要用「信号」的方式来通知进程。

信号是进程间通信机制中唯一的异步通信机制,因为可以在任何时候发送信号给某一进程,一旦有信号产生,我们就有下面这几种,用户进程对信号的处理方式。
信号事件的来源主要有硬件来源(如键盘 Cltr+C )和软件来源(如 kill 命令)。
1.执行默认操作。Linux 对每种信号都规定了默认操作,例如,上面列表中的 SIGTERM 信号,就是终止进程的意思。
2.捕捉信号。我们可以为信号定义一个信号处理函数。当信号发生时,我们就执行相应的信号处理函数。
3.忽略信号。当我们不希望处理某些信号的时候,就可以忽略该信号,不做任何处理。有两个信号是应用进程无法捕捉和忽略的,即 SIGKILL 和 SEGSTOP,它们用于在任何时候中断或结束某一进程。

6. Socket

跨网络与不同主机上的进程之间通信,就需要 Socket 通信了。

六. 中断

1. 中断的定义

在计算机中,中断是系统用来响应硬件设备请求的一种机制,操作系统收到硬件的中断请求,会打断正在执行的进程,然后调用内核中的中断处理程序来响应请求。
中断是一种异步的事件处理机制,可以提高系统的并发处理能力

  • 1
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值