{T}

习题与解析

本文汇集各模块的例题与解析,作为正文的技术补充。按知识模块组织,保留必要的代码与示意图。

一、Linux 指令

1.1 文件系统查找

题目:搜索文件系统中所有包含 std 字符串且以 .h 结尾的文件。

解析:查看全部文件需管理员权限:

bash
sudo find / -name "*std*.h"

忽略大小写可用 -iname;也可结合 grep:

bash
sudo find / -name "*.h" | grep std

1.2 管道与重定向

题目:下面 Shell 程序的作用是什么?

bash
mkfifo pipe1
mkfifo pipe2
echo -n run | cat - pipe1 > pipe2 &
cat < pipe2 > pipe1

解析:前两行创建两个命名管道。第 3 行向输出流写入 run-n 不带回车),经管道传给 catcat> 重定向到管道文件时若无进程读取会阻塞;用 < 读取空管道也会阻塞。整体构成 3 次重定向,路径 pipe1 → pipe2 → pipe1 形成循环,管道中始终有数据(无数据的间隔极短),因此构成无限循环,CPU 占用极高(可用 htop 观察)。

1.3 目录与文件权限

题目:若一个目录是只读权限,其下的文件还可写吗?

解析:Linux 中文件内容不存于目录,目录只保存文件清单。目录只读时,其下文件仍可写(如 foo 目录不可读,foo/bar 仍可写);但创建新文件需修改目录文件,故会报错。

目录只读仍可写文件

1.4 TIME_WAIT 连接数

题目:如何查看处于 TIME_WAIT 状态的连接数量?

解析netstat 会有两行表头,用 tail -n +3 跳过:

code
netstat -a | tail -n +3 | wc -l

1.5 编译安装依赖缺失

题目:编译安装 MySQL 时找不到 libcrypt.so 如何处理?

解析:先查资料(如 StackOverflow,关键词 libcrypt.so not found + 系统名 ubuntu)。该问题多为缺少开发库或链接路径未配置,安装对应包或更新 ldconfig 缓存即可。

1.6 Web 日志分析

题目:根据 access_log 统计访问网站的终端(第 12 列)及访问量 Top3 网页。

解析:用 awk 按列聚合:

bash
cat nginx_logs.txt |\
awk '{tms[$12]++;next}END{for (t in tms) print t, tms[t]}'

Top3 网页可用 sort + uniq -c 统计后取前 3。

1.7 Shell 环境配置文件

题目~/.bashrc~/.bash_profile~/.profile/etc/profile 的区别?

解析:shell 分 login / non-loginsu/sudo 切换或 ssh 远程执行属 login shell,会触发 profile 系列文件;直接 ./a.sh 属 non-login。还分 interactive / non-interactive:交互式终端为 interactive,~/.bashrc 通常只在 interactive 时执行($-i 即 interactive)。ssh 远程执行属 non-login、non-interactive,bashrc 不触发,但 login 触发的 profile 仍执行。

二、内核与态

2.1 内核类型

题目:Unix 与 Mac OS 内核属于哪种类型?

解析:Unix 为宏内核。Mac OS 使用 XNU 内核(X is Not Unix),是一种混合内核,内部含受 Unix 影响极大的宏内核组件。

Mac OS 内核架构

2.2 JVM 线程模型

题目:JVM 的线程是用户态还是内核态线程?

解析:JDK 1.1 时 JVM 自管用户级线程,无法利用多核;后改为线程映射模型:Windows 上为 1 对 1,Linux 上为 n 对 m。映射由 OS 自动完成,用户无需干预。

2.3 开机前的键盘输入

题目:开机时系统尚未载入内存,为何能用键盘?

解析:主板 ROM 上有简化版操作系统 BIOS(Basic Input/Output System),在 OS 接管前管理机器并协助加载 OS。现代 OS 接管后替换 BIOS 的中断向量。

2.4 开发操作系统的难度

题目:林纳斯 21 岁写出 Linux,开发操作系统难度如何?

解析:写出内核本身不极难,需掌握基础数据结构、算法与硬件原理,关键是要有参照(如 Minix)。但今日要写出被广泛接受的内核极难——硬件种类、内核能力已远超前,故 Android 等后续系统多基于 Linux 改装。

三、进程与线程

3.1 fork 的进程数

题目:如下程序执行后 Hello World 打印几次?

c
fork()
fork()
fork()
print("Hello World\n")

解析:fork 复制当前进程全部状态。第 1 个 fork 执行 1 次产生 1 个额外进程;第 2 个 fork 执行 2 次产生 2 个;第 3 个 fork 执行 4 次产生 4 个。共 8 个进程执行 print。

3.2 内存一致性模型

题目:考虑 CPU 缓存,对锁/信号量算法有何影响?

解析:涉及内存一致性模型:多线程能否对同地址读到一致值。强一致性(Sequential Consistency)要求所有线程历史一致;弱一致性仅部分时刻一致。CPU 缓存(L1/L2 私有、L3 共享)会导致不一致:Thread1 写入 A=1 先落其 L1,Thread2 从内存读到旧值,造成竞争。自旋锁 while(!cas(&lock,0,1)) 在缓存未回写时可能让两线程同时进入临界区。Java 用 volatile 强制读等待写完成,避免此问题。

多核缓存不一致

3.3 悲观锁 vs 乐观锁场景

题目:各举 2 个悲观锁、乐观锁应用场景。

解析:二者都能保证最终一致,但体验不同。乐观锁适合"进步耗时长、合并耗时短":协同编辑(写文章、购物车、配置管理)、视频协作。悲观锁适合"进步耗时短、频繁同步":库存扣减、银行交易、订单状态修改。抢购不适合乐观锁(会导致大量 cas 自旋读取),宜用队列(悲观锁)。性能高低不能一概而论,需看场景。

3.4 多级队列调度实现

题目:用熟悉的语言模拟多级队列调度。

解析:高优任务用 PriorityQueue,普通任务用多级 LinkedListsubmit 按优先级入队;next 先取高优再逐级取普通;yield 让任务主动让出并降级入队,无需线程切换,最大化单核效率。完整 Java 实现见原练习题详解四。

3.5 哲学家就餐的模型选择

题目:若哲学家就餐开销集中在 think(CPU 计算),用什么模型合适?

解析:最多允许两组哲学家同时就餐。开销集中在计算上时,只要保证两组可同时进入临界区即可。要求同时拿起左右叉子的简单方案即可达到 2 组并发。

3.6 其他 IPC 方法

题目:还有哪些未讲到的进程间通信方法?

解析:Android 的 OpenBinder(跨进程线程调用,类似 RPC,底层依赖 Linux 文件系统与 Binder 驱动);使用数据库/普通文件;信号kill -s USR1 9999 向 pid=9999 发送 USR1 信号,目标进程可注册处理。

3.7 服务进程/线程数

题目:磁盘坏了通常是什么情况?

解析:彻底损坏易发现(写入报错、死机);隐蔽的是坏道(小区域不可读写,分硬损坏/软损坏)。损坏前常有性能下降(CPU 升高、I/O Wait 增多、响应变慢),可在监控中察觉。检测坏道:

bash
sudo badblocks -v /dev/sda5

四、内存管理

4.1 哈希页表

题目:能否用哈希表将页编号直接映射到 Frame 编号?

解析:传统页表需预分配大量空间(1T 虚拟内存需约 1G 页表)。基于 HashTable 的页表:键为页编号、值为 Frame 编号,先分配少量条目,缺页时再动态添加键值对,大幅省内存;代价是需计算哈希 + 遍历链表,复杂度约 (O(k)),k 小则趋近 (O(1))。

哈希页表

4.2 大内存分页(Java/Go)

题目:Java 与 Go 默认是否需要开启大内存分页?

解析:前提都是 OS 已开启大页。Go 无 VM,可用 syscall.Madvise 提示内核使用 MADV_HUGEPAGE;Java 加 JVM 参数 -XX:+UseLargePages。是否使用应看应用特性并用 perf 观察 iTLB-load-miss 指标,TLB Miss 高才考虑开启。

4.3 TLB 多路组相联的 LRU

题目:8-way 组相联缓存中如何实现 LRU?

解析:三种思路:

  • 累计值:每条目加使用次数位,硬件比较最小值,空间/定时开销大;
  • 1bit 模拟 LRU:每条目 1 位,置换时选 LRU 位为 0 者;8 位全 1 时统一清零;
  • 搜索树模拟:用 7 个 1-bit 节点构造树(0 左 1 右),每次访问沿路径反转箭头,下一个待淘汰位置即箭头指向的"最久未用"子树。该设计用 bit-tree 在 CPU 内近似 FIFO/LRU,免去链表数据结构,是硬件友好的方案。

搜索树模拟 LRU

4.4 大内存的 GC 优化

题目:内存过大导致一次完整 GC 很慢如何处理?

解析:将内存划分为许多小块,每块可独立执行不同回收策略(类似应用内再虚拟化)。绿色区存活概率最低(类 Eden),蓝色上升,橘黄最高(类老生代),灰色为已申请未用。Java 默认回收器 G1 即采用此分块策略,单块 GC 开销显著降低。

分块 GC

五、文件系统

5.1 socket 文件位置

题目:socket 文件都存在哪里?

解析:socket 无实体文件、只有 inode。可在 /proc/net/tcp 看所有 TCP 连接,在 /proc/[pid]/fd 看进程 socket(数字即 fd);或用 lsof -i -a -p [pid]

5.2 日志冗余处理

题目:日志文件系统的数据冗余如何处理?

解析:修改/删除必然产生冗余,通常不主动压缩,但会做碎片整理(多文件删后拷贝合并、空间紧凑)。结论:不压缩、不处理冗余,以空间换时间提升写入速度。

5.3 哈希索引 vs B+ 树索引

题目:按减少磁盘读写原则,哈希表索引是否更有优势?

解析:哈希表查询单值极快(如按姓名查用户),数据库(含 MySQL)常同时支持两种索引。但哈希表是离散结构、数据分散,范围查找/聚合性能极低(如某区间订单)。哈希表扩容需重算所有节点哈希。B+ 树对 >,<,=,BETWEEN,LIKE 等均有较好性能,哈希表仅适用于等值查询。

5.4 HDFS Master 高可用

题目:Master 宕机影响多大、如何恢复?

解析:早期 Master 是单点(SPoF),故障则系统停转。高可用设计:

  • 维护 Active/StandBy 两个 NameNode;
  • 数据节点同时向两 NN 同步状态;
  • 活动 NN 的操作日志写入 Journal Node(至少 3 个、奇数),待命 NN 从 Journal Node 读日志同步;
  • 节点状态(心跳等)存于 ZooKeeper
  • 故障检测单元探测状态,迅速切换。

HDFS 主从 HA

六、网络与安全

6.1 IPv4 vs IPv6

题目:IPv4 与 IPv6 的区别?

解析:核心在地址空间:IPv4 32 位(约 40 亿),需划分子网 + NAT;IPv6 128 位,地址充裕、无需 NAT,可采用"先随机抽地址、再探测冲突"的邻居发现模式。地址数量差异导致分配模式不同(IPv4 中心化请求/返回,IPv6 可先计算后申请)。

6.2 SSH 能否用 UDP

题目:SSH 能否用 UDP 实现?

解析:SSH 通常基于 TCP(先非对称加密协商密钥,再对称加密传数据)。若自建 UDP 上的可靠性,可替代 TCP 能力,但 SSH 吞吐要求不高、收益有限。需高吞吐安全传输(如远程桌面)可考虑 UDP 上专用协议(如 IBM FASP,仅重传明确缺失的包)。

6.3 epoll Web 服务器架构

题目:用 epoll 架构 Web 服务器应是怎样的?

解析:每个客户端连接即一个 Socket 文件,服务器需处理 I/O 与业务逻辑两部分。

处理层(Processing)

  • 每请求一线程:隔离性好但高并发下线程过多、切换频繁、易雪崩;
  • 线程池:具备反向压力(Back-Pressure),可拒绝部分请求缓解压力;
  • 协程:单内核线程分片给 n 个协程,等待 I/O 时转让资源,无需线程切换,性能最佳(Go 轻量线程、Node.js 任务均属此类)。

I/O 层:监听的 fd 放入 epoll 红黑树,进入高性能状态。读取可选:单线程异步 I/O(仅处理中断)、多线程同步 I/O(高并发浪费 CPU)、零拷贝(mmap 结合 DMA,内核不向用户空间拷贝)。

6.4 预防中间人攻击

题目:如何预防中间人攻击?

解析:核心是守住信任链:离开工位锁屏防物理破解;不收来历不明邮件防证书被装;不用盗版系统/软件(非法证书来源);服务器防攻破(防私钥泄露、防 Root、防数据库被挂马)。安全是红线,需集体维护。

七、虚拟化

7.1 用 Docker 运行 Web 程序

题目:自己尝试用 Docker 执行一个方向的 Web 程序(Spring/Django/Express)?

解析:安装 Docker 后,用 docker-compose.yml 定义多容器环境。开发环境常把所有工具链用 Compose 放一起,线上环境数据库一般不用容器。国内可用 Aliyun 镜像加速器。

7.2 Pod 中多容器共用

题目:为何有多个容器共用一个 Pod 的需求?

解析:Pod 内容器共用网络命名空间(可 localhost 通信)与存储卷。典型为边车模式(Sidecar):主容器将日志/监控写入共享卷,由日志/监控容器上传处理;或跨语言场景(Java 接收视频,传给 OpenCV 容器处理)。Ambassador Container(使节容器) 专门为主容器连接外部服务(如自动探测环境、从远程读全局配置,屏蔽多套数据库环境的差异)。

边车/使节容器

小结

习题覆盖 Linux 指令、内核与态、进程线程、内存管理、文件系统、网络与安全、虚拟化七大模块的核心考点,重点在于将正文概念落到具体场景与命令实现。