操作系统(学习笔记)

1.什么是操作系统?

可以这么说,操作系统是⼀种运⾏在内核态的软件。
它是应⽤程序和硬件之间的媒介,向应⽤程序提供硬件的抽象,以及管理硬件资源
2.系统主要有哪些功能?
操作系统最主要的功能:
处理器(CPU)管理:CPU的管理和分配,主要指的是进程管理。
内存管理:内存的分配和管理,主要利⽤了虚拟内存的⽅式。
外存管理:外存(磁盘等)的分配和管理,将外存以⽂件的形式提供出去。
I/O管理:对输⼊/输出设备的统⼀管理。
除此之外,还有保证⾃⾝正常运⾏的健壮性管理,防⽌⾮法操作和⼊侵的安全性管理。
4.什么是内核?
可以这么说,内核是⼀个计算机程序,它是操作系统的核⼼,提供了操作系统最核⼼的能
⼒,可以控制操作系统中所有的内容。
5.什么是⽤户态和内核态?
内核具有很⾼的权限,可以控制 cpu、内存、硬盘等硬件,出于权限控制的考虑,因此⼤多数
操作系统,把内存分成了两个区域:
内核空间,这个内存空间只有内核程序可以访问;
⽤户空间,这个内存空间专给应⽤程序使⽤,权限⽐较⼩;
⽤户空间的代码只能访问⼀个局部的内存空间,⽽内核空间的代码可以访问所有内存空间。
因此,当程序使⽤⽤户空间时,我们常说该程序在⽤户态执⾏,⽽当程序使内核空间时,程
序则在内核态执⾏。
6.⽤户态和内核态是如何切换的?
应⽤程序如果需要进⼊内核空间,就需要通过系统调⽤,来进⼊内核态:
内核程序执⾏在内核态,⽤户程序执⾏在⽤户态。当应⽤程序使⽤系统调⽤时,会产⽣⼀个
中断。发⽣中断后, CPU 会中断当前在执⾏的⽤户程序,转⽽跳转到中断处理程序,也就是
开始执⾏内核程序。内核处理完后,主动触发中断,把 CPU 执⾏权限交回给⽤户程序,回到
⽤户态继续⼯作。
 
7.并⾏和并发有什么区别?
并发就是在⼀段时间内,多个任务都会被处理;但在某⼀时刻,只有⼀个任务在执⾏。单核
处理器做到的并发,其实是利⽤时间⽚的轮转,例如有两个进程ABA运⾏⼀个时间⽚之
后,切换到BB运⾏⼀个时间⽚之后又切换到A。因为切换速度⾜够快,所以宏观上表现为
在⼀段时间内能同时运⾏多个程序。
并⾏就是在同⼀时刻,有多个任务在执⾏。这个需要多核处理器才能完成,在微观上就能同
时执⾏多条指令,不同的程序被放到不同的处理器上运⾏,这个是物理上的多个进程同时进
⾏。

 

8.什么是进程上下⽂切换?
对于单核单线程 CPU ⽽⾔,在某⼀时刻只能执⾏⼀条 CPU 指令。上下⽂切换 (Context
Switch) 是⼀种将 CPU 资源从⼀个进程分配给另⼀个进程的机制。从⽤户⾓度看,计算机能
够并⾏运⾏多个进程,这恰恰是操作系统通过快速上下⽂切换造成的结果。在切换的过程
中,操作系统需要先存储当前进程的状态 (包括内存空间的指针,当前执⾏完的指令等等)
再读⼊下⼀个进程的状态,然后执⾏此进程。
9.进程有哪些状态?
当⼀个进程开始运⾏时,它可能会经历下⾯这⼏种状态:
上图中各个状态的意义:
运⾏状态( Runing ):该时刻进程占⽤ CPU
就绪状态( Ready ):可运⾏,由于其他进程处于运⾏状态⽽暂时停⽌运⾏;
阻塞状态( Blocked ):该进程正在等待某⼀事件发⽣(如等待输⼊/输出操作的完成)
⽽暂时停⽌运⾏,这时,即使给它CPU控制权,它也⽆法运⾏;

当然,进程还有另外两个基本状态:
创建状态( new ):进程正在被创建时的状态;
结束状态( Exit ):进程正在从系统中消失时的状态;

 

10.什么是僵⼫进程?
僵⼫进程是已完成且处于终⽌状态,但在进程表中却仍然存在的进程。
僵⼫进程⼀般发⽣有⽗⼦关系的进程中,⼀个⼦进程的进程描述符在⼦进程退出时不会释
放,只有当⽗进程通过 wait() waitpid() 获取了⼦进程信息后才会释放。如果⼦进程退出,
⽽⽗进程并没有调⽤ wait() waitpid(),那么⼦进程的进程描述符仍然保存在系统中。

11.什么1是孤⼉进程?
⼀个⽗进程退出,⽽它的⼀个或多个⼦进程还在运⾏,那么这些⼦进程将成为孤⼉进程。孤
⼉进程将被 init 进程 (进程 ID 1 的进程) 所收养,并由 init 进程对它们完成状态收集⼯
作。因为孤⼉进程会被 init 进程收养,所以孤⼉进程不会对系统造成危害。

12.进程有哪些调度算法?
进程调度就是确定某⼀个时刻CPU运⾏哪个进程,常见的进程调度算法有:

先来先服务
⾮抢占式的调度算法,按照请求的顺序进⾏调度。有利于长作业,但不利于短作业,因为短
作业必须⼀直等待前⾯的长作业执⾏完毕才能执⾏,⽽长作业又需要执⾏很长时间,造成了
短作业等待时间过长。另外,对I/O密集型进程也不利,因为这种进程每次进⾏I/O操作之后又
得重新排队。
短作业优先
⾮抢占式的调度算法,按估计运⾏时间最短的顺序进⾏调度。长作业有可能会饿死,处于⼀
直等待短作业执⾏完毕的状态。因为如果⼀直有短作业到来,那么长作业永远得不到调度。
优先级调度
为每个进程分配⼀个优先级,按优先级进⾏调度。为了防⽌低优先级的进程永远等不到调
度,可以随着时间的推移增加等待进程的优先级。
时间⽚轮转
将所有就绪进程按 先来先服务的原则排成⼀个队列,每次调度时,把 CPU 时间分配给队⾸进
程,该进程可以执⾏⼀个时间⽚。当时间⽚⽤完时,由计时器发出时钟中断,调度程序便停
⽌该进程的执⾏,并将它送往就绪队列的末尾,同时继续把 CPU 时间分配给队⾸的进程。
时间⽚轮转算法的效率和时间⽚的⼤⼩有很⼤关系:因为进程切换都要保存进程的信息并且
载⼊新进程的信息,如果时间⽚太⼩,会导致进程切换得太频繁,在进程切换上就会花过多
时间。 ⽽如果时间⽚过长,那么实时性就不能得到保证。
最短剩余时间优先
最短作业优先的抢占式版本,按剩余运⾏时间的顺序进⾏调度。 当⼀个新的作业到达时,其
整个运⾏时间与当前进程的剩余时间作⽐较。如果新的进程需要的时间更少,则挂起当前进
程,运⾏新的进程。否则新的进程等待。

13.进程间通信有哪些⽅

管道:管道可以理解成不同进程之间的对⽩,⼀⽅发声,⼀⽅接收,声⾳的介质可是是空
⽓或者电缆,进程之间就可以通过管道,所谓的管道就是内核中的⼀串缓存,从管道的
⼀端写⼊数据,就是缓存在了内核⾥,另⼀端读取,也是从内核中读取这段数据。
管道可以分为两类:匿名管道命名管道。匿名管道是单向的,只能在有亲缘关系的进
程间通信;命名管道是双向的,可以实现本机任意两个进程通信。
信号 : 信号可以理解成⼀种电报,发送⽅发送内容,指定接收进程,然后发出特定的软
件中断,操作系统接到中断请求后,找到接收进程,通知接收进程处理信号。
⽐如 kill -9 1050 就表⽰给PID1050的进程发送 SIGKIL 信号。Linux系统中常⽤信
号:
1SIGHUP:⽤户从终端注销,所有已启动进程都将收到该进程。系统缺省状态下对
该信号的处理是终⽌进程。
2SIGINT:程序终⽌信号。程序运⾏过程中,按Ctrl+C键将产⽣该信号。
3SIGQUIT:程序退出信号。程序运⾏过程中,按Ctrl+\键将产⽣该信号。
4SIGBUSSIGSEGV:进程访问⾮法地址。
5SIGFPE:运算中出现致命错误,如除零操作、数据溢出等。
6SIGKILL:⽤户终⽌进程执⾏信号。shell下执⾏kill -9发送该信号。
7SIGTERM:结束进程信号。shell下执⾏kill 进程pid发送该信号。
8SIGALRM:定时器信号。
9SIGCLD:⼦进程退出信号。如果其⽗进程没有忽略该信号也没有处理该信号,则
⼦进程退出后将形成僵⼫进程。
消息队列:消息队列就是保存在内核中的消息链表,包括Posix消息队列和System V消息
队列。有⾜够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读⾛队列中
的消息。消息队列克服了信号承载信息量少,管道只能承载⽆格式字节流以及缓冲区⼤⼩
受限等缺点。
共享内存: 共享内存的机制,就是拿出⼀块虚拟地址空间来,映射到相同的物理内存
中 。这样这个进程写⼊的东西,另外的进程上就能看到。共享内存是最快的 IPC
式,它是针对其他进程间通信⽅式运⾏效率低⽽专门设计的。它往往与其他通信机制,如
信号量,配合使⽤,来实现进程间的同步和通信。
信号量:信号量我们可以理解成红绿灯,红灯⾏,绿灯停。它本质上是⼀个整数计数
,可以⽤来控制多个进程对共享资源的访问。它常作为⼀种锁机制,防⽌某进程正在
访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同⼀进程内不同线
程之间的同步⼿段。
信号量表⽰资源的数量,控制信号量的⽅式有两种原⼦

 

线程是进程当中的⼀条执⾏流程。
同⼀个进程内多个线程之间可以共享代码段、数据段、打开的⽂件等资源,但每个线程各⾃
都有⼀套独⽴的寄存器和栈,这样可以确保线程的控制流是相对独⽴的。

线程与进程的⽐较如下:
调度: 进程是资源(包括内存、打开的⽂件等)分配的单位 , 线程是 CPU 调度的单
位 ;
资源:进程拥有⼀个完整的资源平台,⽽线程只独享必不可少的资源,如寄存器和栈;
拥有资源:线程同样具有就绪、阻塞、执⾏三种基本状态,同样具有状态之间的转换关
系;
系统开销:线程能减少并发执⾏的时间和空间开销——创建或撤销进程时,系统都要为之
分配或回收系统资源,如内存空间,I/O设备等,OS所付出的开销显著⼤于在创建或撤销
线程时的开销,进程切换的开销也远⼤于线程切换的开销。

15.线程上下⽂切换了解吗?

这还得看线程是不是属于同⼀个进程:
当两个线程不是属于同⼀个进程,则切换的过程就跟进程上下⽂切换⼀样;
当两个线程是属于同⼀个进程,因为虚拟内存是共享的,所以在切换时,虚拟内存这些资
源就保持不动,只需要切换线程的私有数据、寄存器等不共享的数据 ;
所以,线程的上下⽂切换相⽐进程,开销要⼩很多。

16.线程有哪些实现⽅式?
主要有三种线程的实现⽅式:
内核态线程实现 :在内核空间实现的线程,由内核直接管理直接管理线程。

⽤户态线程实现 :在⽤户空间实现线程,不需要内核的参与,内核对线程⽆感知。

 

混合线程实现 :现代操作系统基本都是将两种⽅式结合起来使⽤。⽤户态的执⾏系统负
责进程内部线程在⾮阻塞时的切换;内核态的操作系统负责阻塞线程的切换。即我们同时
实现内核态和⽤户态线程管理。其中内核态线程数量较少,⽽⽤户态线程数量较多。每个
内核态线程可以服务⼀个或多个⽤户态线程。

 

17.线程间如何同步?
同步解决的多线程操作共享资源的问题,⽬的是不管线程之间的执⾏如何穿插,最后的结果
都是正确的。
我们前⾯知道线程和进程的关系:线程是进程当中的⼀条执⾏流程。所以说下⾯的⼀些同步
机制不⽌针对线程,同样也可以针对进程。
临界区:我们把对共享资源访问的程序⽚段称为 临界区 ,我们希望这段代码是 互斥 的,保
证在某时刻只能被⼀个线程执⾏,也就是说⼀个线程在临界区执⾏时,其它线程应该被阻⽌
进⼊临界区。

 

 

临界区不仅针对线程,同样针对进程。
临界区同步的⼀些实现⽅式:
1
使⽤加锁操作和解锁操作可以解决并发线程/进程的互斥问题。
任何想进⼊临界区的线程,必须先执⾏加锁操作。若加锁操作顺利通过,则线程可进⼊临界
区;在完成对临界资源的访问后再执⾏解锁操作,以释放该临界资源。
加锁和解锁锁住的是什么呢?可以是 临界区对象 ,也可以只是⼀个简单的 互斥量 ,例如互斥
量是 0 ⽆锁, 1 表⽰加锁。

 

根据锁的实现不同,可以分为 忙等待锁和 ⽆忙等待锁
忙等待锁和 就是加锁失败的线程,会不断尝试获取锁,也被称为⾃旋锁,它会⼀直占⽤
CPU
⽆忙等待锁 就是加锁失败的线程,会进⼊阻塞状态,放弃CPU,等待被调度。
2信号量
信号量是操作系统提供的⼀种协调共享资源访问的⽅法。
通常信号量表⽰资源的数量,对应的变量是⼀个整型( sem )变量。
另外,还有两个原⼦操作的系统调⽤函数来控制信号量的,分别是:
P 操作:将 sem 1 ,相减后,如果 sem < 0 ,则进程/线程进⼊阻塞等待,否则继续,
表明 P操作可能会阻塞;
V 操作:将 sem 1 ,相加后,如果 sem <= 0 ,唤醒⼀个等待中的进程/线程,表明 V
操作不会阻塞;
P 操作是⽤在进⼊临界区之前,V 操作是⽤在离开临界区之后,这两个操作是必须成对出现
的。

18.什么是死锁?
在两个或者多个并发线程中,如果每个线程持有某种资源,⽽又等待其它线程释放它或它们
现在保持着的资源,在未改变这种状态之前都不能向前推进,称这⼀组线程产⽣了死锁。通
俗的讲就是两个或多个线程⽆限期的阻塞、相互等待的⼀种状态。

19.死锁产⽣有哪些条件?
死锁产⽣需要同时满⾜四个条件:
互斥条件 :指线程对⼰经获取到的资源进⾏它性使⽤,即该资源同时只由⼀个线程占
⽤。如果此时还有其它线程请求获取获取该资源,则请求者只能等待,直⾄占有资源的线
程释放该资源。
请求并持有条件 :指⼀个 线程⼰经持有了⾄少⼀个资源,但又提出了新的资源请求,⽽
新资源⼰被其它线程占有,所以当前线程会被阻塞,但阻塞 的同时并不释放⾃⼰已经获取
的资源。
不可剥夺条件 :指线程获取到的资源在⾃⼰使⽤完之前不能被其它线程抢占,只有在⾃
⼰使⽤完毕后才由⾃⼰释放该资源。
环路等待条件 :指在发⽣死锁时,必然存在⼀个线程——资源的环形链,即线程集合
{T0T1T2,…… Tn} T0 正在等待⼀ T1 占⽤的资源,Tl1正在等待 T2⽤的资
源,…… Tn 在等待⼰被 T0占⽤的资源。
 
20.如何避免死锁呢?
产⽣死锁的有四个必要条件:互斥条件、持有并等待条件、不可剥夺条件、环路等待条件。
避免死锁,破坏其中的⼀个就可以。
消除互斥条件
这个是没法实现,因为很多资源就是只能被⼀个线程占⽤,例如锁。
消除请求并持有条件
消除这个条件的办法很简单,就是⼀个线程⼀次请求其所需要的所有资源。
消除不可剥夺条件
占⽤部分资源的线程进⼀步申请其他资源时,如果申请不到,可以主动释放它占有的资源,
这样不可剥夺这个条件就破坏掉了。
消除环路等待条件
可以靠按序申请资源来预防。所谓按序申请,是指资源是有线性顺序的,申请的时候可以先
申请资源序号⼩的,再申请资源序号⼤的,这样线性化后就不存在环路了。

 

21.活锁和饥饿锁了解吗?
饥饿锁:
饥饿锁,这个饥饿指的是资源饥饿,某个线程⼀直等不到它所需要的资源,从⽽⽆法向前推
进,就像⼀个⼈因为饥饿⽆法成长。
活锁:
在活锁状态下,处于活锁线程组⾥的线程状态可以改变,但是整个活锁组的线程⽆法推进。
活锁可以⽤两个⼈过⼀条很窄的⼩桥来⽐喻:为了让对⽅先过,两个⼈都往旁边让,但两个
⼈总是让到同⼀边。这样,虽然两个⼈的状态⼀直在变化,但却都⽆法往前推进。

22.什么是虚拟内存?
我们实际的物理内存主要是主存,但是物理主存空间有限,所以⼀般现代操作系统都会想办
法把⼀部分内存块放到磁盘中,⽤到的时候再装⼊主存,但是对⽤户程序⽽⾔,是不需要注
意实际的物理内存的,为什么呢?因为有 虚拟内存 的机制。
简单说,虚拟内存是操作系统提供的⼀种机制,将不同进程的虚拟地址和不同内存的物理地
址映射起来。
每个进程都有⾃⼰独⽴的地址空间,再由操作系统映射到到实际的物理内存。
于是,这⾥就引出了两种地址的概念:
程序所使⽤的内存地址叫做虚拟内存地址Virtual Memory Address
实际存在硬件⾥⾯的空间地址叫物理内存地址Physical Memory Address)。
23.什么是内存分段?
程序是由若⼲个逻辑分段组成的,如可由代码分段、数据分段、栈段、堆段组成。不同的段
是有不同的属性的,所以就⽤分段(Segmentation)的形式把这些段分离出来。
分段机制下的虚拟地址由两部分组成,段号段内偏移量
虚拟地址和物理地址通过段表映射,段表主要包括段号段的界限

 

24.什么是内存分页?
是把整个虚拟和物理内存空间切成⼀段段固定尺⼨的⼤⼩。这样⼀个连续并且尺⼨固定
的内存空间,我们叫Page)。在 Linux 下,每⼀的⼤⼩为 4KB
访问分页系统中内存数据需要两次的内存访问 :⼀次是从内存中访问页表,从中找到指定的
物理页号,加上页内偏移得到实际物理地址,第⼆次就是根据第⼀次得到的物理地址访问内
存取出数据。

25.多级页表知道吗?
操作系统可能会有⾮常多进程,如果只是使⽤简单分页,可能导致的后果就是页表变得⾮常
庞⼤。
所以,引⼊了多级页表的解决⽅案。
所谓的多级页表,就是把我们原来的单级页表再次分页,这⾥利⽤了 局部性原理 ,除了顶级
页表,其它级别的页表⼀来可以在需要的时候才被创建,⼆来内存紧张的时候还可以被置换
到磁盘中。

 

26.什么是块表?
同样利⽤了 局部性原理 ,即在⼀段时间内,整个程序的执⾏仅限于程序中的某⼀部分。相应
地,执⾏所访问的存储空间也局限于某个内存区域。
利⽤这⼀特性,把最常访问的⼏个表项存储到访问速度更快的硬件,于是计算机科学家
们,就在 CPU 芯⽚中,加⼊了⼀个专存放程序最常访问的表项的 Cache,这个 Cache
TLBTranslation Lookaside Buffer) ,通常称为表缓存、转址旁路缓存、快表等。

 

27.分页和分段有什么区别?
段是信息的逻辑单位,它是根据⽤户的需要划分的,因此段对⽤户是可见的 ;页是信息
的物理单位,是为了管理主存的⽅便⽽划分的,对⽤户是透明的。
段的⼤⼩不固定,有它所完成的功能决定;页的⼤⼩固定,由系统决定
段向⽤户提供⼆维地址空间;页向⽤户提供的是⼀维地址空间
段是信息的逻辑单位,便于存储保护和信息的共享,页的保护和共享受到限制。
28.什么是交换空间?
操作系统把物理内存(Physical RAM)分成⼀块⼀块的⼩内存,每⼀块内存被称为页(page)。当
内存资源不⾜时,Linux把某些页的内容转移⾄磁盘上的⼀块空间上,以释放内存空间。磁盘
上的那块空间叫做交换空间(swap space),⽽这⼀过程被称为交换(swapping)。物理内存和交换
空间的总容量就是虚拟内存的可⽤容量。
⽤途:
物理内存不⾜时⼀些不常⽤的页可以被交换出去,腾给系统。
程序启动时很多内存页被⽤来初始化,之后便不再需要,可以交换出去
 
30.硬链接和软链接有什么区别?
硬链接就是在⽬录下创建⼀个条⽬,记录着⽂件名与 inode 编号,这个 inode 就是源⽂件
inode。删除任意⼀个条⽬,⽂件还是存在,只要引⽤数量不为 0。但是硬链接有限制,
它不能跨越⽂件系统,也不能对⽬录进⾏链接
软链接相当于重新创建⼀个⽂件,这个⽂件有独⽴的 inode,但是这个⽂件的内容是另
外⼀个⽂件的路径,所以访问软链接的时候,实际上相当于访问到了另外⼀个⽂件,所
软链接是可以跨⽂件系统的,甚⾄⽬标⽂件被删除了,链接⽂件还是在的,只不过打
不开指向的⽂件了⽽已。
31.零拷贝了解吗?
假如需要⽂件传输,使⽤传统I/O,数据读取和写⼊是⽤户空间到内核空间来回赋值,⽽内核
空间的数据是通过操作系统的I/O接⼜从磁盘读取或者写⼊,这期间发⽣了多次⽤户态和内核
态的上下⽂切换,以及多次数据拷贝。

 

32.聊聊阻塞与⾮阻塞 I/O 同步与异步 I/O
阻塞I/O
先来看看阻塞 I/O,当⽤户程序执⾏ read ,线程会被阻塞,⼀直等到内核数据准备好,并把
数据从内核缓冲区拷到应⽤程序的缓冲区中,当拷过程完成, read 才会返回。
注意,阻塞等待的是 内核数据准备好 数据从内核态拷⻉到⽤户态 这两个过程

 

⾮阻塞I/O
⾮阻塞的 read 请求在数据未准备好的情况下⽴即返回,可以继续往下执⾏,此时应⽤程序不
断轮询内核,直到数据准备好,内核将数据拷到应⽤程序缓冲区, read 调⽤才可以获取到
结果。

 

基于⾮阻塞的I/O多路复⽤
我们上⾯的⾮阻塞I/O有⼀个问题,什么问题呢?应⽤程序要⼀直轮询,这个过程没法⼲其它
事情,所以引⼊了I/O 多路复⽤技术。
当内核数据准备好时,以事件通知应⽤程序进⾏操作。

 

33.详细讲⼀讲I/O多路复⽤?
我们先了解什么是I/O多路复⽤?
我们在传统的I/O模型中,如果服务端需要⽀持多个客户端,我们可能要为每个客户端分配⼀
个进程/线程。
不管是基于重⼀点的进程模型,还是轻⼀点的线程模型,假如连接多了,操作系统是扛不住
的。
所以就引⼊了I/O多路复⽤ 技术。
简单说,就是⼀个进程/线程维护多个Socket,这个多路复⽤就是多个连接复⽤⼀个进程/线
程。

我们来看看I/O多路复⽤三种实现机制:
select
select 实现多路复⽤的⽅式是:
将已连接的 Socket 都放到⼀个⽂件描述符集合fd_set,然后调⽤ select 函数将fd_set集合拷
到内核⾥,让内核来检查是否有⽹络事件产⽣,检查的⽅式很粗暴,就是通过遍历fd_set的⽅
式,当检查到有事件产⽣后,将此 Socket 标记为可读或可写, 接着再把整个fd_set回⽤
户态⾥,然后⽤户态还需要再通过遍历的⽅法找到可读或可写的 Socket,再对其处理。
select 使⽤固定度的 BitsMap,表⽰⽂件描述符集合,⽽且所⽀持的⽂件描述符的个数是有
限制的,在Linux 系统中,由内核中的 FD_SETSIZE 限制, 默认最⼤值为 1024 ,只能监听
0~1023 的⽂件描述符。
select机制的缺点:
1)每次调⽤select,都需要把fd_set集合从⽤户态拷贝到内核态,如果fd_set集合很⼤时,那
这个开销也很⼤,⽐如百万连接却只有少数活跃连接时这样做就太没有效率。
2)每次调⽤select都需要在内核遍历传递进来的所有fd_set,如果fd_set集合很⼤时,那这个
开销也很⼤。
3)为了减少数据拷贝带来的性能损坏,内核对被监控的fd_set集合⼤⼩做了限制,⼀般为
1024,如果想要修改会⽐较⿇烦,可能还需要编译内核。
4)每次调⽤select之前都需要遍历设置监听集合,重复⼯作。
poll
poll 不再⽤ BitsMap 来存储所关注的⽂件描述符,取⽽代之⽤动态数组,以链表形式来组
织,突破了select 的⽂件描述符个数限制,当然还会受到系统⽂件描述符限制。
但是 poll select 并没有太⼤的本质区别,都是使⽤线性结构存储进程关注的Socket集合,因
此都需要遍历⽂件描述符集合来找到可读或可写的Socke,时间复杂度为O(n),⽽且也需要在
⽤户态与内核态之间拷⽂件描述符集合,这种⽅式随着并发数上来,性能的损耗会呈指数
级增
epoll
epoll 通过两个⽅⾯,很好解决了 select/poll 的问题。
第⼀点,epoll 在内核⾥使⽤红⿊树来跟踪进程所有待检测的⽂件描述字,把需要监控的
socket 通过epoll_ctl() 函数加⼊内核中的红⿊树⾥,红⿊树是个⾼效的数据结构,增删查⼀般
时间复杂度是O(logn) ,通过对这棵⿊红树进⾏操作,这样就不需要像 select/poll 每次操作时
都传⼊整个 socket 集合,只需要传⼊⼀个待检测的 socket减少了内核和⽤户空间⼤量的数
据拷和内存分配
第⼆点, epoll 使⽤事件驱动的机制,内核⾥维护了⼀个链表来记录就绪事件,当某个 socket
有事件发⽣时,通过回调函数,内核会将其加⼊到这个就绪事件列表中,当⽤户调⽤
epoll_wait() 函数时,只会返回有事件发⽣的⽂件描述符的个数,不需要像 select/poll 那样轮
询扫描整个 socket 集合,⼤⼤提⾼了检测的效率。

epoll 的⽅式即使监听的 Socket 数量越多的时候,效率不会⼤幅度降低,能够同时监听的
Socket 的数⽬也⾮常的多了,上限就为系统定义的进程打开的最⼤⽂件描述符个数。因
⽽,epoll 被称为解决 C10K 问题的利器

epoll 的⽅式即使监听的 Socket 数量越多的时候,效率不会⼤幅度降低,能够同时监听的
Socket 的数⽬也⾮常的多了,上限就为系统定义的进程打开的最⼤⽂件描述符个数。因
⽽,epoll 被称为解决 C10K 问题的利器

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值