操作系统八股问——连载ing
目录
1. 操作系统在进行线程切换时候需要做哪些动作?
什么是用户态和内核态?
进程之间的通信方式有哪些?
操作系统中进程有哪种状态?
什么是僵尸进程、孤儿进程?
线程和进程有什么区别?
聊聊进程调度算法?
什么是软中断?什么是硬中断?
为什么要有虚拟内存?
什么是分段?分页?
分页与虚拟内存之间有什么关系?
CPU使用率和CPU负载指什么?它们之间的联系呢?
请你说下常用的Linux命令?
I/O是什么?
为什么网络I/O会被阻塞?
网络I/O阻塞的常见场景?
I/O模型有哪些?
同步和异步的区别?
阻塞与非阻塞的区别?
同步、异步、阻塞、非阻塞I/O的区别?
到底什么是Reactor?
Select、Poll、Epoll之间有什么区别?
什么是物理地址?什么是逻辑地址?
听说过linux CFS吗?
负数的二进制如何表示?
1.操作系统在进行线程切换时候需要做哪些动作?
操作系统中,线程切换是指将CPU控制权从一个线程转移到另一个线程的过程。与进程切换相比线程切换的开销较小,因为同一进程的线程是共享相同的地址空间和资源。
线程切换时,主要动作如下:
-
保存当前线程的上下文(如 CPU寄存器、栈指针等)到线程控制块(TCB)中
-
更新当前的线程状态
-
选择下一个要执行的线程,更新调度信息。
-
恢复下一个线程的上下文,恢复CPU寄存器、栈指针、程序计数器等信息,确保线程能够从上次中断的地方继续执行,开始执行其任务。
-
什么是用户态和内核态?
用户态(UserModel)和内核态(Kernel Mode)是操作系统中两种运行模式。用于区分应用程序和操作系统内核的操作权限。
-
用户态:应用程序在用户态下运行,权限较低,不能直接访问硬件或进行特权操作。应用程序需要通过系统调用与内核进行通信,由内核代为执行敏感操作。用户态优势:安全性高,即使程序出现问题也不会影响操作系统的稳定性。
-
内核态:内核态是操作系统内核运行的模式,具有最高的权限,可以直接访问硬件资源和执行各种特权操作(如内存管理、进程调度)。当程序执行系统调用或者硬件中断时候,操作系统会将其切换为内核态。
-
进程之间的通信方式有哪些?
-
管道(Pipes):管道是一种单向通信方式,用于在父进程和子进程之间或者同一主机上的不同进程之间传递数据。它可以是匿名的,也可以是命名的。
-
命名管道(Named Pipes):与匿名管道类似,但具有一个在文件系统中有名的路径,允许不相关的进程之间进行通信。
-
消息队列(MessageQueues):消息队列允许一个进程向另一个进程发送消息,消息在队列中按顺序存储,并且接收方可以按需接收。
-
共享内存(Shared Memory):共享内存允许多个进程访问同一块内存区域,从而实现快速的数据交换。但需要注意同步问题,以避免竞态条件和数据一致性问题。
-
信号量(Semaphores):信号量是一种同步原语,用于管理对共享资源的访问。它可以用于实现进程间的互斥访问和同步操作。
-
信号(Signal):信号是一种异步的通信方式,用于通知目标你进程发生了某个事件。信号常用于进程之间发送中断或终止命令令。
-
套接字(Sockets):套接字允许在网络上的不同主机上的进程进行通信,是实现网络通信的基础。
-
文件(File):进程可以通过读写文件来进行通信,这种方式通常用于进程之间的间接通信,例如使用临时文件或者共享文件。
-
操作系统中进程有哪种状态?
在操作系统中,进程的状态通常包括以下几种:
-
就绪状态(Ready):进程已分配到必要的资源,具备执行条件,等寺CPU调度程序分配处理器时间。一旦CPU空闲并选择该进程,就会从就绪状态进入运行状态。
-
运行状态(Running):进程正在使用CPU执行指令。在单核CCPU中,只有一个进程处于运行状态,而在多核CPU中,多个进程可以同时运行。
-
阻塞状态(Blocked/Waiting):进程因为等待某种事件(如l/O操作作完成、等待某个信号等)而暂时停止运行。处于阻塞状态的进程不能被CPU调度,必须等到所需事件发生后,才能转为就绪状态,
-
新建状态(New):进程正在创建但尚未进入就绪队列。操作系统为新进程分配资源(如内存),当准备就绪后,进程会进入就绪状态。
-
终止状态(Terminated):进程执行完毕或因某种原因被终止,进入终止状态。操作系统会回收该进程所占用的资源。
-
什么是僵尸进程、孤儿进程?
僵尸进程(Zombie Process):进程已经终止,但其父进程未对其进行回收(调用Wait函数)。僵尸进程占用系统的进程表质,但不再消耗其他资源。操作系统会等待其父进程来获取它的终止状态信息,清除僵尸进程。
孤儿进程(Orphan Process):父进程提前终止,子进程继续运行,成为孤儿进程。操作系统会将孤儿进程托管给init进程(Linux系统中的PID为1的进程),由init进程来收养并清理这些孤儿进程。
-
线程和进程有什么区别?
-
进程:资源分配的基本单位。每个进程都有独立的内存空间(代码段、数据段、堆栈等),可以看作是一个正在运行的程序实例。进程之间是相互独立的。
-
线程:是CPU调度的基本单位,属于进程,一个进程中可以包含多个线程。线程共享进程的内存空间和资源(如文件句柄、数据段),但是每个线程都有独立的栈和寄存器。
-
资源消耗不同:进程时需要为其分配独立的内存空间和系统资源,创建和切换进程的开销较大。线程间共享进程的资源,创建线程所需的开销较小,线程切换的开销也远小于进程切换。
-
通信方式差异:因为各自独立的内存空间,进程间通信(IPC)较为复杂,需要使用管道、消息队列、共享内存、套接字等方式。同一进程内的线程共享内存空间,因此线程直接读写内存即可,但注意需要使用同步机制避免数据错误。
-
聊聊进程调度算法?
-
先来先服务(FCFS,First-Come,First-Served):按照进程到达的顺序进行调度,适用于批处理系统。简单易实现,但可能造成"长任务"拖延其他任务的执行。
-
短作业优先服务(SJF,Shortest Job First):优先调度执行时间最短的进程,能减少平均等待时间。分为非抢占式和抢占式(SRTFShortest Remaining Time First)。但它需要预先知道任务执行时间,不适用于交互式系统。
-
优先级调度(Priority Scheduling):根据进程的重要性(优先级)来调度,优先级高的进程先执行。适用于需要不同优先级服务的场景。可能导致"低优先级进程"长期得不到调度,造成饥饿现象。
-
时间片轮转(RR,Round Robin):为每个进程分配固定的时间间片,时间片结束后调度下一个进程。适用于交互式系统,能提系统响应性。时间片的选择对系统性能有重要影响。
-
最高响应比优先(HRRN,Highest Response Ratio Next):通过计算响应比来决定下一个被调度的进程,适合在批处理环境中平衡长短任务的等待时间,防止短任务过多导致长任务饥饿。
-
多级反馈队列调度(MLFQ, Multilevel Feedback Queue):结合多个调度策略,通过将进程放入不同优先级的队列,实现灵活的调度机制。优先级较高的进程先被调度,随着执行时间增加,进程可能被降至低优先级队列。适合多任务、多类型的操作系统。
-
什么是软中断?什么是硬中断?
软中断和硬中断是操作系统处理外部或内部事件的两种中断方式:
-
硬中断(Hardware Interrupt):是由硬件设备(如键盘、网卡、定时器等)触发的中断信号。当硬件设备需要与CPU交互(如数据传输完成、定时中断等),会通过硬中断通知CPU。硬中断具有高优先级,通常会立即打断当前执行的程序,进行中断处理。
-
软(软件)中断(Software Interrupt):是由软件程序触发的中断,通常通过执行特殊指令或系统调用产生的。软中断用于程序运行中请求操作系统的服务,如文件读写、进程调度等。软中断的优先级一般低于硬中断。
SoftIRQ软中断
上述的软中断实际上称为软件中断比较合适,因为操作系统中有软中断听(SoftIRQ)的概念,两者还是有所区别的。
软中断(SoftIRQ)是Linux内核中用于延迟处理部分中断任务的机制刷,属于中断处理的下半部。由于硬中断处理程序(上半部)需要尽可能短暂,以减少对系统的影响,因此将一些耗时的工作延迟到软中断中执行。
即硬中断处理程序触发,然后内核在适当的时候调度执行。
内核维护一个软中断向量表,包含不同类型的软中断(如网络接收、网络发送、定时器等)。当需要触发软中断时,内核将相应的软中断标记为待处理状态,并在稍后的时间点(如在中断上下文退出时或在内核的调度点)执行这些软中断处理程序。
软中断(SoftIRQ)和软件中断(Software Interrupt)的区别如下:
-
触发源不同:软件中断由用户程序通过指令触发;软中断通常由硬中断处理程序在内核中触发。
-
目的不同:软件中断用于实现系统调用,提供用户态与内核态的接口;软中断用于延迟处理需要较长时间的中断任务,减少硬中断处理时间。
-
执行上下文不同:软件中断导致从用户态切换到内核态;软中断所在内核态执行,不涉及用户态。
-
为什么要有虚拟内存?
虚拟内存的主要作用是提升系统效率和简化内存管理。
-
内存拓展能力:虚拟内存允许程序运行在比实际物理内存大的地址空间上。即使物理内存不足,系统也可以通过交换将不常用的内存页移动到磁盘中,使得多个程序能够同时运行。
-
进程隔离:每个进程拥有独立的虚拟地址空间,防止进程间的内存访问冲突,提高系统稳定性和安全性;使用虚拟内存,操作系统可以通过页面表设置访问权限,防止非法访问。
-
简化内存管理:操作系统可以更灵活地分配和回收内存,无需手动考虑物理内存分布问题;虚拟内存可以将程序逻辑地址与物理地址解耦。
-
什么是分段?分页?
分段(Segmentation)和分页(Paging)是操作系统中用于内存管理的两种方式,目的是提高内存利用率并简化程序的管理
-
分段(Segmentation):是一种根据程序逻辑结构划分内存的方式,例如将程序分为若干个段(如代码段、数据段、堆栈段等),每个段有独立的段号和段内偏移量。每个段可以有不同的大小,段的长度取决于程序的实际需求,段与段之间可能不连续。分段管理提供了一种更贴近程序结构的内存管理方式,有助于提高程序的可读性和维护性。
-
分页(Paging):是一种将物理内存和逻辑内存划分为固定大小的页(Page)和页框(Frame)的方式,每个页和页框的大小相同。逻辑地址空间被划分为若干个固定大小的页,物理内存则波划分为相同大小的页框,页通过页表映射到页框。分页管理解决了内存碎片问题,但程序的逻辑结构和内存的物理结构不再一致。
-
分页与虚拟内存之间有什么关系?
-
虚拟内存:分页是实现虚拟内存的重要手段,虚拟内存允许程序使用比物理内存更大的逻辑地址空间。操作系统通过页表将虚拟地址映射到物理地址,实现按需加载和页面置换。
-
页面置换算法:当物理内存不足时,操作系统会将不常用的页置换到磁盘中,并在需要时重新加载。常见的页面置换算法有LRU(最近最少使用)、FIFO(先进先出)等。
-
CPU使用率和CPU负载指什么?它们之间的联系呢?
-
CPU使用率:是指在特定时间窗口内,CPU用于处理任务的日时间百分比(例如,使用率70%表示CPU70%的时间在运行)用户进程或内核任务,30%的时间空闲)。
使用率通常细分为:
-
用户态时间(usertime):运行用户进程的时间。
-
内核态时间(systemtime):运行系统调用或内核任务的时间。
-
空闲时间(idletime):CPU无任务可执行时的时间。
-
CPU负载:CPU负载表示系统中需要被CPU处理的任务数量(包括运行队列中的任务和等待CPU时间片的任务,常用指标:1分钟、5分钟、15分钟的平均负载)。
负载值解读:
-
小于等于CPU核心数:系统任务通常能被及时处理,性能轻好。
-
大于CPU核心数:系统可能出现任务排队,性能下降。
两者之间的关系:
CPU使用率和负载均与系统任务量相关,但含义不同:
-
CPU使用率反映CPU工作的忙碌程度。
-
CPU负载反映等待处理的任务数量(不仅包括CPU繁忙任务,还包括 I/O 等待的任务)。
常见可能的组合:
高使用率,高负载:CPU任务超负荷,系统性能瓶颈可能在计算能力。
低使用率,高负载:可能存在大量I/O密集型任务或锁竞争。
高使用率,低负载:CPU忙碌,但任务调度良好。
低使用率,低负载:系统空闲,资源未被充分利用。
-
请你说下常用的Linux命令?
-
文件与目录操作
-
ls:列出当前目录的文件与子目录,常用参数 -l 详情信息 -a 包括隐藏文件
-
cd:切换目录
-
mkdir:创建新目录
-
rm:删除文件或目录,如果删除文件加上-f 参数,删除目录 则加上 -r参数
-
cp:复制文件或目录,cp -r 用于递归复制目录
-
mv:移动或者重命名文件或者目录
-
-
文件内容查看
-
cat:查看文件内容,常用于查看小型的文本文件
-
more/less:分页查看文件内容,less支持向上翻页,适合查看大文件
-
tail:查看文件末尾的若干行,tail-f 用于监控文件内容变化,如日志文件。
-
head:查看文件的开头几行。
-
-
系统管理
-
ps:显示当前运行的进程列表,ps aux 可以查看所有用户的进程。
-
top/htop:实时查看系统中的进程状态和资源使用情况。
-
kill/killadd:终止进程,kill后面跟进程ID,killall后面跟进程名
-
df:显示文件系统的磁盘使用情况
-
du:统计目录或文件所占用的磁盘空间,du -h 以人类可读的格式显示。
-
-
网络配置与调试
-
ping:测试与目标主机的连通性
-
ifconfig/ip:查看和配置网络接口信息,ifconfig逐渐被ip命令替代。
-
netstat/ss:查看网络连接和端口的使用情况,ss是netstat的替代品,提供更详细的信息。
-
curl/wget:发送HTTP请求或下载文件,curl更适合api调试,wget则用于下载文件。
-
-
文件权限与用户管理
-
chmod:修改文件或目录权限,常用模式如chmod755。
-
chown:更改文件或目录的所有者。
-
useradd/userdel:添加或删除用户。
-
passwd:修改用户密码。
-
-
I/O是什么?
I/O(Input/Output,输入/输出)是计算机系统中用于数据传输的机制,指的是在计算机和外部设备(如键盘、显示器、硬盘等)之间,或在计算机内部组件(比如内存与CPU)之间的数据传输过程。I/O操作包括输入操作(数据从外部设备读取到计算机)和输出操作(数据从计算机传输到外部设备)。
I/O 设备类型
-
块设备:如硬盘、SSD,它们以固定大小的块为单位进行读写操作,适合随机访问。
-
字符设备:如键盘、鼠标、串口,它们以字符流的方式进行数据传输,适合顺序读写。
-
为什么网络I/O会被阻塞?
网络I/O会被阻塞 是因为在进行网络数据传输的时候,操作系统会在等待数据发送和接收完成之前,将线程挂起,直到数据传输完成以后,才恢复进程。
阻塞的主要原因是:
-
等待数据到达或发送完成:当进程尝试从网络套接字中读取数据时候,如果数据尚未当道,操作系统就会使得进程进入阻塞状态,直到数据到达为止。同样,当数据未能立即发送出去时,发送操作也可能被阻塞,等待缓冲区有空闲时间。
-
系统资源有限:当系统资源(如 网络缓冲区、连接数等)被占满的时候,进一步的 I/O请求可能会被阻塞,等到资源释放的时候才能继续
-
默认的阻塞行为:大多数的网络API在默认情况下都是阻塞的,即调用这些API时,如果条件不满足,会使得调用者等待直到I/O操作完成。
-
网络I/O阻塞的常见场景?
连接的阻塞:
-
accept()阻塞:服务器调用accept()时,会阻塞在这个调用上,直到有新的客户端连接请求到来。此时,服务器进程会等待客户端的连接,无法继续执行其他操作。
-
connect()阻塞:客户端在调用connect()尝试连接服务器的时候,如果连接不能立即建立(如 服务器响应慢、网络不通畅),connect()会阻塞,直到连接成功或超时。
数据传输的阻塞:
-
recv()阻塞和read()阻塞:当使用这些函数从套接字中读取数据时候,如果缓冲区没有数据(比如对方尚未发送数据),进程就会被阻塞,直到数据到达。
-
send()和write()阻塞:当缓冲区已满(如网络阻塞或对方接受缓慢),数据无法立即写入时,send()和write()会阻塞,等待缓冲区有空闲时候再发送数据。
-
I/O模型有哪些?
常见的I/O模型有以下几种:
-
阻塞I/O(Blocking I/O):调用I/O操作时,进程会被阻塞,直到数据准备好或操作完成后才继续执行。
-
非阻塞I/O(Non-blocking I/O操作不会阻塞进程,如果数据没有准备好,立即返回错误或状态,进程可以继续执行其他操作。
-
I/O多路复用(l/OMultiplexing):使用select、poll、epoll等系统调用,允许程序同时等待多个I/O操作,当其中任意一个就绪时进行处理。
-
信号驱动I/O(Signal-drivenl/O):在数据准备好时,内核通过信号通知进程进行I/O操作,进程在接收到信号后再进行数据读取或写入
-
异步l/O(Asynchronous I/O):发起I/O请求后立即返回,内核在后台完成l/0操作,并在操作完成时通知进程。进程不需要等待I/O完成即可继续执行其他任务。
阻塞的执行单元解释:如果是单线程的程序用进程来描述合适一些些,即称之为进程会被阻塞。如果多线程的程序用线程合适一些,即称之为线程会被阻塞
-
同步和异步的区别?
同步(Synchronous)和异步(Asynchronous)是两种不同的任务执行方式,主要区别在于任务的执行是否需要等待其他任务完成:
-
同步:
在同步操作中,任务需要等待前一个任务完成后才能继续。调用者发起请求后,会被阻塞,直到任务完成并返回结果。调用者必须等待结果才能进行后续操作。例如,程序执行一个读取文件的操作时,必须等到文件内容完全读取到内存后,才能继续进行后续的代码执行。
-
异步:
在异步操作中,任务在发出请求后可以立即继续执行,不需要等等待请求的完成。请求的结果会通过回调、Promise、Future等机制在任务完成后通知调用者。例如,程序执行一个网络请求时,可以在请求发送后立即继续执行其他操作,不需要等待请求的响应,当响应到达时会收到通知扣进行处理。
同步编程 实践案例
-
数据库事务处理
在一个典型的银行转账系统中,为了确保数据的一致性和完整性,月所有的数据库操作都必须以同步的方式进行。例如,当用户从一个贴户向另一个账户转账时,系统首先会检查源账户是否有足够的余额,然后扣除相应应的金额,并将这笔钱添加到目标账户中。整个过程需要严格按照顺序执行,不能有任何一步被打断或跳过。这是因为任何中间状态的变化都可能导致数据不不一致的问题,比如部分转账成功而另一部分失败。因此,在这种情况下使用同步调用是非常必要的。
-
文件读写操作
考虑一个文件上传服务,它接收客户端发送的大文件并将这些文件保存到服务器上。由于文件传输本身就是一个耗时的过程,如果采用同步方式处理,则在整个上传期间,客户端将无法执行其他任何操作,直到上传完成为止。这种方式虽然简单直接,但用户体验较差,尤其是在网络条件不不佳的情况下。然而在某些特殊场合下,如对安全性要求极高的环境中,可能还是会选择同步方法来保证数据传输的安全性。
异步编程的实践案例
-
Web应用中的异步请求
现代Web应用程序广泛采用了AJAX技术来进行页面局部刷新,而不必重新加载整个页面。例如,在社交网络平台上发表评论时,用户是交评论后不必等待服务器响应就可以继续浏览其他内容;与此同时,后台会异步地将新评论添加到帖子下方。这样不仅提高了用户的交互体验,也减轻了服务器的压力。
-
高井发下的任务队列
对于高并发场景下的任务调度问题,可以利用Java中的Executorservice配合Future接口实现异步任务管理。以电商平台为例,每当有订单生成时,系统会立即返回确认信息给用户,同时异步地处理诸如库存检查、物流安排非等一系列后续工作。通过这种方式,即使面对大量的并发请求,也能保证系统的稳定性和高效性。
-
使用CompletableFuture简化异步编程
Java8引入了CompletableFuture类,极大地简化了异步编程的复杂度。假没我们正在开发一个在线购物平台,需要从多个第三方API获取商品详情(如价格、图片等)。我们可以创建多个CompletableFuture实例并行地发起HTTP请求,一旦所有请求均已完成,再合并结果展示给用户。这种方法不仅提高了程序的响应速度,还使得代码更加简洁易读。
// 创建线程池
ExecutorService executor = Executors.newFixedThreadPool(10);// 定义异步任务
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {// 模拟获取商品基本信息return "商品基本信息";
}, executor);CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {// 模拟获取商品图片信息return "商品图片信息";
}, executor);// 组合多个异步任务的结果
CompletableFuture<Void> allFutures = CompletableFuture.allOf(future1, future2);// 等待所有任务完成并打印结果
allFutures.thenRun(() -> {try {System.out.println("基本信息: " + future1.get());System.out.println("图片信息: " + future2.get());} catch (InterruptedException | ExecutionException e) {e.printStackTrace();}
});// 关闭线程池
executor.shutdown();
-
阻塞与非阻塞的区别?
阻塞(Blocking)和非阻塞(Non-blocking)是描述程序在选进行I/0操作时的行为方式,主要区别在于调用者是否需要等待操作完成:
阻塞:在阻塞操作中,调用方在发出请求后会等待操作完成,期间调用方会被挂起,不能继续执行其他任务,直到请求的操作完成。
例如,读取文件内容时,若数据未准备好,调用read方法的程序会被限且塞,直到数据读取完成
非阻塞:在非阻塞操作中,调用方在发出请求后立即返回,即使操作未完成,调用方可以继续执行其他任务。若数据未准备好,操作会返回一个状态(如EAGAIN)而不是阻塞。
例如,在非阻塞模式下读取文件,若数据尚未准备好,read调用会立即返回,程序可以执行其他逻辑。
阻塞的优点与缺点:
优点:编程逻辑简单,易于实现,适合于按顺序处理任务的场景。调用者不需要关心操作是否完成,只需要等待结果。
缺点:如果操作耗时较长,会导致系统资源(如CPU、线程)被长时间占用,特别是在高并发场景下,会导致大量的线程处于等待状态,降低系统性能。
非阻塞的优点与缺点:
优点:可以避免调用方长时间等待,提高系统的并发处理能力,特别是在需要处理大量I/O操作的场景中,非阻塞可以使程序更高效地使用CPU;
缺点:编程复杂度较高,因为调用方需要处理操作未完成的情况(如循环检查状态),需要设计更复杂的状态管理和重试机制。
-
同步、异步、阻塞、非阻塞I/O的区别?
要注意,不同场景下同一个名词意义可能不同。这里关于同步、异步、阻塞、非阻塞这几个概念是基于I/O场景下讲的。
关于I/O的阻塞、非阻塞、同步、异步:
阻塞和非阻塞指的是发起I/O请求后,用户线程状态的不同,阻塞I/O在数据未准备就绪的时候会阻塞当前用户线程,而非阻塞I/O会立马返回一个错误,不会阻塞当前用户线程。
同步和异步是指,内核的I/O拷贝实现,当数据准备就绪后,需要将内核空间的数据拷贝至用户空间,如果是同步I/O那么用中线程会等待拷贝的完成,而异步I/O则这个拷贝过程用户线程该干嘛可以去干嘛,当内核拷贝完毕之后会"通知"用户线程。
总的来说:同步异步,是根据I/O响应方式的不同进行划分的;阻塞、非阻塞是指用户线程是否被阻塞。
-
到底什么是Reactor?
Reactor是一种用于处理并发I/O事件的设计模式,特别适合于网络服务器的开发。它通过事件驱动机制和非阻塞I/O,能够高效地处理大量并发连接。
Reactor模式的核心思想是将I/O事件与相应的处理程序解耦,并通过事件分发器(Event Demultiplexer)来管理事件和响应操作。
Reactor的工作方式:
事件驱动:Reactor通过监听多个事件源(如Socket连接、读写事件),在有事件发生时调用对应的处理程序(Handler)。
非阻塞I/O:使用非阻塞I/O横型,Reactor能够在单个或少数线程中高效处理大量I/O操作,避免了线程的频繁切换
事件分发与处理:Reactor会将收到的事件(如连接到达、数据可读、数据可写)分发给相应的事件处理器,处理器对事件进行处理里。
-
Select、Poll、Epoll之间有什么区别?
它们都是操作系统中用于多路复用I/O的机制
-
select :早期的I/O多路复用机制,使用固定长度的数组表示文件描述符集。每次调用select时都需要重新构建和检查文件描述符集。支持的文件描述符数量有限(通常为1024),在大规模连接的场景下效率较低。
-
poll :
poll与select类似,但使用动态数组来存储文件描述符,因此没有select的最大连接数限制。每次调用时仍需遍历全部描述符,在处理大量连接时效率不高。
-
epoll :
epoll是Linux系统对select和poll的优化,提供了边缘触发(ET)和水平触发(LT)模式。不会遍历所有文件描述符,而是通过事件通知的方式,只处理实际发生变化的描述符,适合高并发服务器。epoll在注册文件描述符后,只需调用一次添加操作,后续的事件管理更高效。
-
什么是物理地址?什么是逻辑地址?
-
物理地址:物理地址是计算机内存中真正的内存单元地址,由内存管理单元(MMIU)直接访问。它表示数据在物理内存中的实际存储位置,是由硬件层面决定的。
物理地址直接对应到内存芯片上的某个位置,它是CPU在访问内存时经过地址转换后的实际地址。
-
逻辑地址(虚拟地址):逻辑地址是程序在运行时看到的地址空间,由CPU生成,用于内存的访问和操作。逻辑地址在程序编写和编译时使用,并由操作系统通过地址转换机制(如页表)映射到物理地址。
每个进程拥有独立的逻辑地址空间,从而实现了进程间的内存隔隔离,增强了系统的安全性和稳定性。
-
听说过linux CFS吗?
Linux CFS(Completely Fair Scheduler,全公平调度器)是Linux内核自2.6.23版本起引入的一种进程调度算法,用于替代原来的O(1)调度器。它以公平性为核心设计目标,旨在使每个任务(进程或线程)能按照其优先级占用CPU的时间片段,尽可能公平地分配CPU资源。
CFS的核心特点
-
完全公平:每个任务按照权重分配CPU时间,权重由任务的优先级(nice值)决定。尽量保证每个任务都能按比例公平地获得CPU资源。
-
时间度量:使用虚拟运行时间(vruntime)衡量每个任务消耗的CPU时间,越低优先级越高。
-
红黑树管理任务:所有可运行的任务存储在红黑树中,按vruntime排序,最左节点(最小vruntime)优先获得CPU调度。红黑树的插入、删除操作复杂度为O(logN),相比O(1)调度器得高,但仍然性能优异。
-
可扩展性强:支持多核调度,能很好地处理从嵌入式系统到服务器集群的各种应用场景。
-
负数的二进制如何表示?
在计算机中,负数的二进制表示通常采用补码的方式。
补码(Two's Complement)是一种对二进制数的编码方式,用于表示示有符号整数,既可以表示正数,也可以表示负数。
-
唯一的零表示:在补码中,零的表示唯一:000000000000。其他表示方式(如原码和反码)可能出现正负零的问题。
-
简化运算:使用补码表示后,减法运算可以转化为加法运算(如(a-b=a+(-b)))。简化了硬件电路的设计。
-
对称性:补码表示的数值范围是对称的。