承接上文,本文总结了计算机基础学科(包括数据结构、计算机组成原理、操作系统、计算机网络等)常见的一些面试问题,以便随时查看。

常见的进程调度算法有哪些

  • 先来先服务调度算法:处于就绪态的进程按先后顺序链入到就绪队列中,而先来先去服务调度算法按就绪进程进入就绪队列的先后次序选择当前最先进入就绪队列的进程来执行,直到此进程阻塞或结束,才进行下一次的进程选择调度。

  • 短进程优先调度算法:是一种按照进程执行时间长短进行调度的算法,即优先调度执行时间短的进程。

  • 优先级调度算法:优先级调度算法又称优先权调度算法。优先级调度算法每次从就绪队列中选择优先级最高的进程,将处理机分配给它,使之投入运行。

  • 高响应比优先调度算法:该算法是对 FCFS 调度算法和 SPF 调度算法的一种综合平衡,同时考虑每个进程的等待时间和估计的运行时间。在每次进行进程调度时,先计算就绪队列中每个进程的响应比,从中选出响应比最高的进程投入运行。

  • 时间片轮转调度算法:时间片轮转调度算法主要适用于分时系统。每次调度时,把 CPU 分配给队首进程,并令其执行一个时间片。当执行的时间片用完时,由一个计时器发出时钟中断请求,调度程序便据此信号来停止该进程的执行,并将它送往就绪队列的末尾;然后,再把处理机分配给就绪队列中新的队首进程,同时也让它执行一个时间片。

  • 多级反馈队列调度算法:是一种综合性的调度算法,它将进程队列分成多个队列,每个队列有不同的优先级,每个队列的时间片大小也不同。

什么是大端、小端,如何判断大端和小端

什么是大端、小端

大端和小端是指在多字节数据类型的存储方式中,高位字节和低位字节的存储顺序。大端模式是指高位字节存储在低地址,低位字节存储在高地址;小端模式是指低位字节存储在低地址,高位字节存储在高地址。

如何判断大端和小端

  • 利用联合体的特性,将一个多字节的变量和一个字节的变量存放在同一个地址空间中,通过判断该变量的第一个字节的值来判断系统的大小端模式。如果第一个字节的值为 0,那么该系统是大端模式;如果第一个字节的值为 1,那么该系统是小端模式。

  • 利用强制类型转换,将一个整型变量的地址强制转换为一个字符型指针,然后通过判断该指针所指向的地址的值来判断系统的大小端模式。如果该指针所指向的地址的值为 0,那么该系统是大端模式;如果该指针所指向的地址的值为 1,那么该系统是小端模式。

进程通信的方式有哪些

  • 管道是一种进程间通信的方式,建立在具有血缘关系的进程之上。管道是一种单向通信方式,即发送进程以字符流形式将大量数据送入管道,接收进程可从管道接收数据,二者利用管道进行通信。管道是基于字节流的,管道内部已完成同步机制,数据具有一致性,不被外界打扰。

  • 消息队列是一种进程间通信的方式,它是一种消息传递机制,即发送进程将消息发送到消息队列,接收进程从消息队列中接收消息。消息队列是基于消息的,消息队列中的消息具有类型,接收进程可以选择接收特定类型的消息。

  • 共享内存是一种进程间通信的方式,它是一种共享内存区域的机制,即多个进程共享同一块内存区域,进程可以直接访问这块内存区域,从而实现进程间通信。

  • 信号量是一种进程间通信的方式,它是一种计数器,用于控制多个进程对共享资源的访问。

  • 信号是一种进程间通信的方式,它是一种软件中断,用于通知进程发生了某个事件。

  • Socket 是一种进程间通信的方式,它是一种网络通信机制,可以在不同的主机之间进行通信。

进程有多少种状态,如何转换

进程有五种状态:创建、就绪、执行、阻塞、终止:

  • 创建:一个进程启动,首先进入创建状态,需要获取系统资源创建进程控制块(PCB:Process Control Block)完成资源分配。
  • 就绪:在创建状态完成之后,进程已经准备好,处于就绪状态,但是还未获得处理器资源,无法运行。
  • 运行:获取处理器资源,被系统调度,当具有时间片开始进入运行状态。如果进程的时间片用完了就进入就绪状态。
  • 阻塞:在运行状态期间,如果进行了阻塞的操作,此时进程暂时无法操作就进入到了阻塞状态,在这些操作完成后就进入就绪状态。等待再次获取处理器资源,被系统调度,当具有时间片就进入运行状态。
  • 终止:进程结束或者被系统终止,进入终止状态。

进程和线程的区别

  • . 进程有独立的地址空间,线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间;
  • 进程和线程切换时,需要切换进程和线程的上下文,进程的上下文切换时间开销远远大于线程上下文切换时间,耗费资源较大,效率较低;
  • 进程的并发性较低,线程的并发性较高;
  • 每个独立的进程有一个程序运行的入口、顺序执行序列和程序的出口,但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制;
  • 系统在运行的时候会为每个进程分配不同的内存空间;而对线程而言,除了 CPU 外,系统不会为线程分配内存(线程所使用的资源来自其所属进程的资源),线程组之间只能共享资源;
  • 一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进程都将崩溃。因此多进程要比多线程健壮。

介绍一下死锁,产生的必要条件,产生的原因,如何避免死锁

什么是死锁

死锁是指两个或多个进程在执行过程中,因争夺资源而造成的一种僵局,若无外力作用,它们都将无法继续执行下去。

产生的必要条件

  • 互斥条件:进程要求对所分配的资源进行排它性控制,即在一段时间内某资源仅为一进程所占用。
  • 请求和保持条件:当进程因请求资源而阻塞时,对已获得的资源保持不放。
  • 不剥夺条件:进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。
  • 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

产生的原因

  • 系统资源的竞争:通常系统中拥有的不可剥夺资源,其数量不足以满足多个进程运行的需要,使得进程在运行过程中,会因争夺资源而陷入僵局,如磁带机、打印机等。
  • 进程推进顺序非法:进程在运行过程中,请求和释放资源的顺序不当,也会导致死锁。
  • 资源分配不当:系统在资源分配过程中,本身也可能发生错误,如本来应该分配给进程 A 的资源,却分配给了进程 B,这样也可能导致死锁。

如何避免死锁

  • 死锁的预防:破坏互斥条件、破坏请求和保持条件、破坏不剥夺条件、破坏循环等待条件。
  • 死锁的避免:在资源分配过程中,采用银行家算法,动态地分配资源,避免进程间发生死锁。
  • 死锁的检测与解除:通过进程的资源分配图,检测系统中是否存在死锁。采用撤销进程、回收资源等方法,解除死锁。

介绍一下分段和分页

  • 分段是将程序分成若干个逻辑段,每个段可以包含一个模块或若干个模块,每个段的长度是不固定的,每个段都有一个段名和段长,段名是一个符号,段长是指该段所包含的字节数。分段的主要目的是为了方便程序员编写和修改程序,同时也可以更好地利用内存空间,避免内存碎片的产生。

  • 分页是将程序和数据分成固定大小的页。每个页都有一个页号和页框号,页号是页在程序或数据中的逻辑地址,页框号是页在内存中的物理地址。分页的主要目的是为了实现非连续分配,以便解决内存碎片问题,或者说分页是由于系统管理的需要。

介绍一下共享内存

共享内存是一种允许两个或多个进程访问同一块内存的进程间通信方式。共享内存是两个正在运行的进程之间共享和传递数据的一种非常有效的方式。

共享内存的主要优点是速度快,因为数据不需要在进程之间复制,而是直接在内存中传递。共享内存的主要缺点是需要进程之间进行同步,以避免数据的冲突和竞争条件。

介绍一下虚拟内存和物理内存

虚拟内存和物理内存都是计算机中的内存概念,但它们在实现方式和作用上有所不同。

物理内存是计算机实际物理上存在的内存,也被称为主存储器。它是用来存储程序和数据的地方,数据可以被 CPU 直接访问。物理内存的容量是有限的,因此它通常被操作系统分配给运行程序的进程。

虚拟内存则是一种将物理内存和硬盘空间结合起来的技术。它将物理内存扩展到了硬盘上,使得运行的程序可以访问比物理内存更大的内存空间。虚拟内存由操作系统管理,可以分配给不同的进程使用。当进程需要访问虚拟内存时,操作系统会将需要的部分从硬盘上读取到物理内存中,并将不需要的部分暂时写入硬盘,以便为其他进程或操作系统腾出更多的物理内存空间。

虚拟内存的使用可以让多个进程共享物理内存,并且可以提高系统的整体性能和稳定性,因为操作系统可以更好地管理物理内存的使用。虚拟内存的一个重要作用是,它可以使得进程能够访问比物理内存更大的内存空间,因为它使用硬盘空间作为缓存,允许运行大型应用程序和操作系统。

TCP 和 UDP 的区别是什么

TCP(传输控制协议)和 UDP(用户数据报协议)都是互联网协议中的传输层协议,它们在传输数据时有一些区别:

  • 连接:TCP 是面向连接的协议,UDP 是无连接的协议。TCP 通过三次握手建立连接,数据传输结束后需要四次挥手断开连接。而 UDP 在传输数据之前不需要建立连接,也不需要断开连接。
  • 可靠性:TCP 是一种可靠的协议,它通过序号、确认和重传等机制来保证数据传输的可靠性。如果数据丢失或损坏,TCP 会自动重传数据,直到接收方正确接收到数据为止。而 UDP 则没有任何可靠性保障,它只是将数据报发送给接收方,如果数据在传输过程中丢失或损坏,UDP 不会自动重传数据。
  • 传输效率:UDP 比 TCP 传输效率高。UDP 不需要建立连接、维护状态等,因此可以更快地传输数据。但是,由于 UDP 没有可靠性保障,如果出现数据丢失或损坏,需要应用层自己处理。
  • 消息大小:TCP 可以传输大型数据,而 UDP 只能传输小型数据。TCP 在传输数据时会将数据分成多个小块,每个小块都有序号和确认机制,可以保证数据的完整性。而 UDP 每个数据包的大小限制在 64KB 以内,超过这个限制需要应用层进行分割。
  • 应用场景:TCP 适合用于可靠性要求高、数据量较大的场景,例如文件传输、网页访问等。而 UDP 适合用于实时性要求高、数据量较小的场景,例如语音通话、视频会议等。

TCP 三次握手四次挥手的过程是什么

三次握手

  1. 客户端向服务器发送 SYN 报文,表示请求连接。
  2. 服务器接收到 SYN 报文后,发送一个 ACK 报文,表示确认收到客户端请求,并且向客户端发送一个 SYN 报文,表示同意连接。
  3. 客户端接收到服务器的 SYN 和 ACK 报文后,向服务器发送一个 ACK 报文,表示确认连接建立成功。

三次握手完成后,客户端和服务器之间建立了一个可靠的连接,可以进行数据传输。

四次挥手

  1. 客户端向服务器发送一个 FIN 报文,表示要关闭连接。
  2. 服务器接收到 FIN 报文后,发送一个 ACK 报文,表示确认收到客户端的请求,但是还没有准备好关闭连接。
  3. 服务器准备好关闭连接后,向客户端发送一个 FIN 报文,表示要关闭连接。
  4. 客户端接收到服务器的 FIN 报文后,发送一个 ACK 报文,表示确认收到服务器的请求,然后等待两个 MSL (最长报文段寿命)后自动关闭连接。

四次挥手完成后,客户端和服务器之间的连接被释放,不再进行数据传输。

介绍一下 OSI 七层模型

OSI 七层模型是一种网络协议的分层模型,它把网络协议从逻辑上分为了 7 层,每一层都有相关、相对应的物理设备。这 7 层分别为:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。

这 7 层的具体功能如下:

  1. 物理层:定义了物理媒介的规范,如传输速率、信号类型、线路编码等。
  2. 数据链路层:为物理层提供服务,定义了数据在物理媒介上的传输规范,如帧的格式、数据的传输和接收、差错校验等。
  3. 网络层:负责在不同的网络之间进行数据传输,包括路由选择、拥塞控制、逻辑寻址等。
  4. 传输层:负责提供端到端的数据传输,包括数据的分段、传输控制、差错恢复等。
  5. 会话层:管理不同设备之间的会话,包括会话的建立、维护和结束。
  6. 表示层:负责数据的格式转换、加密解密、数据压缩等。
  7. 应用层:负责向用户提供网络服务,包括电子邮件、文件传输、远程登录等。

TCP 如何实现可靠传输

  1. 超时重传机制:TCP 通过使用确认和超时机制来检测丢失的分组并进行重传。当发送方发送一个分组后,会等待接收方发送确认信息,如果在指定的时间内没有收到确认信息,TCP 就会认为这个分组丢失了,然后重新发送。
  2. 滑动窗口机制:TCP 采用滑动窗口技术来控制传输的速度。发送方和接收方都有一个窗口大小的参数,发送方根据接收方发送的确认信息来调整窗口大小,从而保证传输的可靠性和效率。
  3. 流量控制:TCP 使用流量控制来防止发送方发送过多的数据导致接收方的缓存区溢出。接收方可以向发送方发送窗口大小信息,告诉发送方还能接收多少数据,从而实现流量控制。
  4. 拥塞控制:TCP 通过拥塞控制来避免网络拥塞。发送方会根据网络的拥塞情况来调整发送速率,从而避免过多的数据包在网络中堆积导致网络拥塞。

通过上述可靠传输机制,TCP 协议可以在网络不可靠、有丢失和错误的情况下,保证数据传输的可靠性和正确性,从而被广泛应用于各种应用场景。

TCP 和 UDP 的使用场景

  • TCP 适用于要求数据传输可靠性和完整性的场景,如文件传输、电子邮件、网页浏览、远程登录等。由于 TCP 提供了可靠的数据传输和错误处理,这些应用能够保证数据的正确性和完整性,但是 TCP 的建立连接和维护状态等操作会增加传输的时延,适合对速度要求不是特别高的应用。

  • UDP 适用于对实时性和传输速度要求较高的场景,如视频会议、实时游戏等。UDP 不保证数据传输的可靠性,但是它传输速度快,且不需要建立连接和维护状态等操作,适合对实时性和传输速度要求较高的应用场景。

UDP 怎么实现可靠传输

  • 应用层重传:在应用层实现数据的重传机制,当收到 ACK 包时,如果发现某个数据包没有收到 ACK 包的确认,则重新发送该数据包,直到收到 ACK 包的确认。

  • 数据包校验和:在数据包中添加校验和,用来检测数据包是否发生错误,如果发现数据包发生错误,则进行重传。

  • 超时重传:发送方在发送数据包时,设置一个超时时间,如果在该时间内没有收到 ACK 包的确认,则进行数据包的重传。

  • 序列号机制:在发送数据包时,为每个数据包添加一个序列号,接收方收到数据包后,对数据包进行排序,如果发现数据包乱序,则进行重排序。

介绍一下滑动窗口机制

滑动窗口机制是一种流量控制方法,它允许发送方在停止并等待确认前连续发送多个分组,而不必每发送一个分组就停下来等待确认,从而增加数据传输的速率提高应用的吞吐量。

滑动窗口机制通过动态改变窗口大小来调节两台主机间数据传输。滑动窗口机制的基本原理是:发送方和接收方各自维护一个窗口,窗口大小是动态变化的,窗口大小的变化取决于网络的拥塞情况和接收方的处理能力。

浏览器从输入 URL 到页面显示内容,中间发生了什么

  1. DNS 解析:浏览器根据 URL 中的主机名进行 DNS 解析,将域名解析成 IP 地址。
  2. TCP 连接:浏览器使用 HTTP 协议通过 TCP 与服务器建立连接。
  3. 发送 HTTP 请求:浏览器向服务器发送 HTTP 请求,请求中包含请求方法、请求头部、请求正文等内容。
  4. 服务器处理请求:服务器接收到请求后,会根据请求的内容进行处理,处理完后会将响应结果返回给浏览器。
  5. 接收 HTTP 响应:浏览器接收到 HTTP 响应,响应中包含响应头部、响应状态码、响应正文等内容。
  6. 解析 HTML:浏览器根据响应内容中的 HTML 标签和文本内容,解析成 DOM 树。
  7. 加载 CSS 和 JavaScript:浏览器根据 HTML 中的链接标签和脚本标签,加载相应的 CSS 和 JavaScript 文件,并执行其中的代码。
  8. 渲染页面:浏览器根据 DOM 树和 CSS 样式表中的样式信息,将页面渲染出来,包括布局、绘制等过程。
  9. 关闭 TCP 连接:浏览器在完成页面渲染后,会关闭与服务器之间的 TCP 连接。

总的来说,浏览器从输入 URL 到页面显示内容,经历了 DNS 解析、TCP 连接、HTTP 请求、服务器处理请求、HTTP 响应、解析 HTML、加载 CSS 和 JavaScript、渲染页面、关闭 TCP 连接等多个步骤。

介绍一下 DNS 解析过程以及 DNS 劫持

DNS 解析过程

  1. 浏览器首先会检查本地缓存,看是否已经存在该域名的解析结果。如果存在,则直接使用缓存中的解析结果。
  2. 如果本地缓存中不存在该域名的解析结果,则会向本地 DNS 服务器发送查询请求。本地 DNS 服务器一般由 ISP(Internet Service Provider)提供,它会缓存一些常用的域名解析结果。如果本地 DNS 服务器缓存中存在该域名的解析结果,则直接返回给浏览器。
  3. 如果本地 DNS 服务器缓存中也不存在该域名的解析结果,则会向根域名服务器发送查询请求。根域名服务器会告诉本地 DNS 服务器该域名对应的顶级域名服务器的 IP 地址。
  4. 本地 DNS 服务器会向顶级域名服务器发送查询请求。顶级域名服务器会告诉本地 DNS 服务器该域名对应的权威域名服务器的 IP 地址。
  5. 本地 DNS 服务器向权威域名服务器发送查询请求。权威域名服务器会返回该域名的解析结果,本地 DNS 服务器将结果缓存起来,并将结果返回给浏览器。
  6. 浏览器使用该域名对应的 IP 地址与服务器建立连接,并获取相应的资源。

DNS 劫持

DNS 劫持指的是黑客通过某种手段篡改了 DNS 解析结果,将用户访问的域名指向了恶意服务器,从而实现网络攻击。常见的 DNS 劫持方式包括:

  • DNS 缓存投毒:黑客利用漏洞将恶意的 DNS 解析结果注入到 DNS 缓存中。

  • 劫持 DNS 服务器:黑客攻击 DNS 服务器,修改服务器的 DNS 解析结果。

  • 本地 Hosts 文件劫持:黑客通过修改本地 Hosts 文件,将用户访问的域名指向恶意 IP 地址。

介绍一下 ARP 协议

ARP(Address Resolution Protocol)协议是用于将网络层地址(IP地址)转换为链路层地址(MAC地址)的协议。在进行数据传输之前,需要先获得目标设备的 MAC 地址,才能将数据包通过网络传递到目标设备。这就是 ARP 协议的作用。

具体来说,当一台计算机在发送数据时,会先检查其 ARP 缓存,查看目标设备的 MAC 地址是否已经存在。如果已经存在,则将数据包封装成链路层帧,直接发送给目标设备。如果目标设备的 MAC 地址未知,则需要进行 ARP 请求。

ARP 请求是以广播形式发送的,即发送给本网络内所有的设备。请求中包含发送方的 IP 地址和 MAC 地址,以及目标设备的 IP 地址。当目标设备收到 ARP 请求时,会返回一个 ARP 应答,包含其 MAC 地址。此时发送方就可以获得目标设备的 MAC 地址,并将数据包封装成链路层帧发送给目标设备。

需要注意的是,ARP 协议是基于广播的,因此会产生一定的网络负载。此外,ARP 缓存中的条目是有时限的,一旦过期就需要重新进行 ARP 请求。由于 ARP 协议没有进行认证,因此容易受到 ARP 欺骗攻击。

数据库为什么不用红黑树而用 B+ 树

  1. 磁盘 I/O 效率:相对于红黑树而言,B+ 树可以更好地利用磁盘块的大小,一次 I/O 读取更多的节点,从而降低 I/O 的次数,提高查询效率。
  2. 数据查询效率:B+ 树是一种多路搜索树,因此在进行数据查询时,可以很快定位到需要查找的数据节点。而红黑树的查找时间复杂度为 O(log n),相对较慢。
  3. 数据范围查询:在数据库中,我们常常需要进行范围查询,例如查询某个区间内的所有数据。B+ 树可以支持按照范围进行数据查询,而红黑树则需要对整个树进行遍历。
  4. 内存占用:相对于红黑树而言,B+ 树的每个节点可以存储更多的关键字,因此在内存占用方面更加优秀。

介绍一下单例设计模式

单例设计模式是一种创建型设计模式,它保证一个类只有一个实例,并提供了一个全局访问该实例的入口。

在单例设计模式中,类的构造函数被私有化,以防止外部直接通过构造函数创建多个实例。同时,该类提供一个静态方法用于获取该类唯一的实例。在该方法中,会先判断是否已经存在该实例,如果已经存在则直接返回该实例,如果不存在则创建一个新实例并返回。

单例模式主要用于控制实例的数量,避免不必要的内存占用和对象创建。它可以提供一个全局的访问点,方便其他模块或类访问该实例。在多线程环境下,需要注意线程安全,可以通过加锁或双重检查等方式来保证线程安全。

需要注意的是,单例模式虽然有很多优点,但是也存在一些缺点。例如,单例模式会增加代码的复杂度和可读性,同时也会增加测试的难度。因此,应该在确实需要控制实例数量时才使用单例模式。

介绍一下 B 树和 B+ 树

B 树和 B+ 树都是一种多路平衡查找树,主要用于在磁盘等外存储介质上进行数据的高效组织和访问。

B 树是一种平衡树,每个节点可以有多个子节点,通常用于数据库索引等场景。B 树的每个节点中存储的数据是该节点所有子节点中最大或最小的值。在查找时,从根节点开始,依次查找满足条件的子节点,直到找到目标数据或到达叶子节点。

B+ 树是在 B 树的基础上进行改进的,相对于 B 树,B+ 树的所有数据都存储在叶子节点上。每个节点中只存储关键字,而不存储数据,数据只存储在叶子节点上,从而可以减少非叶子节点的磁盘 I/O 次数。在 B+ 树中,叶子节点之间有一个双向链表连接,可以方便地进行范围查询操作。同时,B+ 树的内部节点可以存储更多的关键字,相对于 B 树可以更好地利用磁盘块的大小,从而提高查询效率。

总体来说,B 树和 B+ 树都是一种非常重要的数据结构,它们可以很好地解决在磁盘等外存储介质上进行数据组织和访问的问题。在实际应用中,需要根据具体场景选择适合的树型结构。