计算机基础 面试题库

收录真实面试常见问题,答案长度适合口头表达;拿不准时可返回相关主题复习。

92个问题 初级 高级
全部难度 初级 中级 高级
逐题查看 显示全部答案
报告错误

网络协议

2个问题
01 HTTP/2 多路复用解决了什么问题?哪种队头阻塞仍然存在? 中级 常见 查看答案 ▾ 收起 ▴

HTTP/2 用流标识标记帧,让多组请求与响应可以在一条连接上交错。已经就绪的响应不必再因为 HTTP/1.1 的响应顺序要求,等待前面的慢响应。但是,所有帧仍通过一条有序的 TCP 字节流传输。一旦 TCP 段丢失,所有 HTTP/2 流的后续字节都要等待重传。因此,多路复用消除的是 HTTP 层响应排队,不是传输层队头阻塞。我会确认实际协商出的协议,并经过真实代理路径测量,再判断延迟变化是否来自多路复用。

延伸阅读 HTTP/2
讲清楚了吗?
09 WebSocket 开启握手如何工作?子协议协商确定了什么? 中级 常见 查看答案 ▾ 收起 ▴

在经典 HTTP/1.1 路径上,客户端请求升级,并发送随机的 Sec-WebSocket-Key 与版本 13。服务端接受时返回 101,并根据该 key 和协议 GUID 计算 Sec-WebSocket-Accept。接受值证明对端理解协议,不代表用户身份。客户端还可以提供一组有顺序的 Sec-WebSocket-Protocol 值;服务端最多选择一个客户端提供的值,随后双方使用该应用协议。我会分别验证 TLS、Origin 策略、身份认证和所选协议,再把会话标为可用。

延伸阅读 WebSocket
讲清楚了吗?

容量与背压

3个问题
02 HTTP/2 流量控制与应用背压有什么区别? 中级 常见 查看答案 ▾ 收起 ▴

HTTP/2 的 DATA 会同时消耗流窗口和连接窗口。接收方释放容量后,用 WINDOW_UPDATE 增加字节额度。但这些窗口不会限制 HEADERS、处理器数量、解析后的对象、数据库工作或应用队列。运行时可能通过可写流返回 false 以及之后的 drain 事件,暴露综合压力。正确的服务既要响应这个信号,也要限制入口并发、正文大小、解码、下游调用和缓冲响应。我会测试对端停止读取的情况,因为正常的小负载很难暴露缺失的背压。

延伸阅读 HTTP/2
讲清楚了吗?
07 网络服务中的端到端背压需要覆盖哪些环节? 高级 常见 查看答案 ▾ 收起 ▴

套接字背压始于内核发送缓冲区填满:阻塞写会等待,非阻塞写会部分完成或报告暂时不可写。服务若继续把响应塞入无界用户态队列,就切断了反馈。我会限制已接收连接、在途处理器、解析后消息、下游调用和待发送字节。消费者变慢时,生产者应暂停,而不是继续创建工作。过载策略可以拒绝、丢弃协议允许丢失的数据或关闭慢连接,但必须明确;再根据队列深度、缓冲字节和尾延迟调整限制。

延伸阅读 网络编程
讲清楚了吗?
11 怎样为经典 WebSocket API 实施背压? 高级 常见 查看答案 ▾ 收起 ▴

经典 API 会把传给 send 的数据排队,并通过 bufferedAmount 提供快照;它没有标准排空事件,也不会自动让生产者减速。我只在连接处于 OPEN 且编码后负载不超过每连接字节预算时准入发送。随后根据消息语义暂停或拒绝生产者、合并可替换状态,或关闭持续缓慢的对端。上限还要覆盖入站消息大小、并发处理器和下游调用。我会让对端停止读取并监控排队字节与内存,因为普通小消息很难暴露缺失的边界。

延伸阅读 WebSocket
讲清楚了吗?

故障处理

5个问题
03 客户端应如何处理 HTTP/2 的 GOAWAY 帧? 高级 偶尔 查看答案 ▾ 收起 ▴

GOAWAY 表示连接不再接受新流,并携带对端可能处理过的最高流标识。客户端应为新工作创建或选择另一个会话,同时给已经接受的流设置有限排空时间。编号更高的本地流可以成为重试候选,但协议信号不能独自决定重试。方法必须能安全重放或受到幂等机制保护,请求正文必须可重新生成,还要考虑中间层可能产生的副作用。我不会盲目重放所有活动请求,尤其不会盲目重放写操作。

延伸阅读 HTTP/2
讲清楚了吗?
06 对于套接字读取方,超时、有序 EOF 和连接复位有什么区别? 中级 常见 查看答案 ▾ 收起 ▴

超时表示操作没有在预算内取得所需进展,并不能证明对端已经失效。有序 EOF 会在缓冲字节读完后表现为空读取,说明对端关闭了发送方向。连接复位表示异常终止,通常以错误形式出现。这三种结果都不能证明对端是否提交了应用事务。我会保留不同错误状态,附上连接阶段和字节计数,由单一所有者关闭资源,并且只在应用幂等语义保证安全时重试。

延伸阅读 网络编程
讲清楚了吗?
10 为什么 WebSocket 重连不足以恢复消息交付? 中级 常见 查看答案 ▾ 收起 ▴

连接中断只说明传输结束,不能说明服务端是否处理了最后一条命令。服务端可能已经提交副作用,只是确认在回程中丢失。我会用带随机扰动和上限的指数退避重连,然后先恢复认证与订阅,再发送新工作。有副作用的命令携带稳定幂等键,使重试返回原结果,而不是重复执行。服务器推送使用已确认的恢复游标;如果保留历史不再覆盖该游标,协议应要求获取新快照,不能静默丢失事件。

延伸阅读 WebSocket
讲清楚了吗?
51 退出状态、管道与 pipefail 会怎样影响 Shell 错误处理? 中级 常见 查看答案 ▾ 收起 ▴

按照约定,零表示成功,每条命令会定义自己的非零结果。特殊参数 $? 很容易被覆盖,因此我会立即保存它,或者直接把命令放进 if 条件。Bash 管道通常报告最后一个阶段,可能掩盖前面阶段的失败。启用 pipefail 后,管道报告最靠右的非零阶段,但使用方提前退出也可能让生产方按预期收到 SIGPIPE。我会为每条管道单独选择策略,保留诊断输出,并在测试中强制每个阶段失败。set -e 的行为依赖语法上下文,因此我不会把它当成异常处理。

延伸阅读 Shell 基础
讲清楚了吗?
78 怎样在不丢失阶段身份的前提下检测 Bash 管道的上游故障? 中级 常见 查看答案 ▾ 收起 ▴

Bash 默认报告最后一条命令的状态,因此成功的消费者可能隐藏失败的生产者。如果任何阶段失败都应让操作失败,我会启用 pipefail;诊断或按状态恢复需要每个值时,还会在管道之后立即复制 PIPESTATUS,因为一次 echo 或赋值就能替换该数组。我会显式分类预期的非零状态,而不是给整条管道加上 || true。发布产物前还要验证既定状态策略并拒绝部分输出,即使文件非空或最终解析器已经成功。

讲清楚了吗?

协议安全

2个问题
04 HPACK 维护什么状态?还需要哪些安全限制? 高级 偶尔 查看答案 ▾ 收起 ▴

HPACK 使用静态表和动态表,让重复的字段名称与值可以通过引用表示。编码与解码上下文具有顺序,并且只属于一条连接;上下文损坏因此可能成为连接错误。压缩不会加密字段。敏感值应使用永不索引的表示,同时仍需 TLS、日志脱敏和访问控制。接收方必须限制解码后的字段数量与总大小,不能信任线上的压缩字节数。我还会限制单字段大小和解码工作,避免很小的字段块触发无界内存或 CPU 消耗。

延伸阅读 HTTP/2
讲清楚了吗?
12 浏览器 WebSocket 边界需要哪些安全检查? 高级 偶尔 查看答案 ▾ 收起 ▴

我会使用 wss,并在升级前按明确允许列表校验浏览器 Origin。Origin 用来防止恶意页面借用环境凭据,不是身份认证,非浏览器客户端也能伪造它。身份来自安全会话、短期连接票据或有界认证交换。每条消息都要限制大小、按 schema 解析、限制速率,并针对目标资源授权,不能永久信任连接时权限。我不会把长期令牌放进 URL 和日志,会迅速关闭未完成认证的连接,并定义不会泄露敏感策略细节的关闭状态码。

延伸阅读 WebSocket
讲清楚了吗?

传输语义

1个问题
05 TCP 为什么需要应用消息分帧?你会怎样测试长度前缀解码器? 中级 常见 查看答案 ▾ 收起 ▴

TCP 交付有序字节流,不保留发送方选择的写入边界。一次接收可能只有部分头或负载,也可能包含多条消息,只要字节顺序不变即可。长度前缀解码器因此要增量缓冲,按约定字节序读取固定宽度长度,拒绝超过配置上限的值,并且只产出完整帧。我会测试头与负载中的每个切分位置、多帧同读、零长度帧、提前 EOF、超长声明和覆盖整个操作的截止时间。

延伸阅读 网络编程
讲清楚了吗?

连接建立

1个问题
08 客户端为什么应把 DNS 结果当作连接候选,而不是单个地址? 高级 偶尔 查看答案 ▾ 收起 ▴

一个主机名可能解析出多个 IPv6 与 IPv4 地址,各自的可达性和延迟不同。只尝试第一项,会让一条故障路径变成应用中断;同时连接全部地址又会浪费资源。成熟客户端会结合解析器顺序和错开的有界候选尝试,取消失败竞争者,并执行一个整体截止时间。我会保留每个候选的失败原因并记录最终地址族。解析成功、传输连接、TLS 握手和应用握手仍是不同阶段,因为前一阶段成功不保证下一阶段成功。

延伸阅读 网络编程
讲清楚了吗?

操作系统模型

1个问题
13 Linux 内核、发行版与 Shell 有什么区别? 初级 常见 查看答案 ▾ 收起 ▴

Linux 是内核,负责调度执行、管理内存与设备、实现文件系统和网络,并暴露系统调用。发行版把选定内核与用户空间库、包管理、服务管理、默认配置和更新策略组合起来。Shell 只是一个用户空间命令解释器,负责启动程序,并为重定向和管道配置文件描述符。这些层可以独立变化。即使两个环境都使用 Linux,从 Ubuntu 复制的 Bash 命令也可能在精简 Fedora 容器中失败,因为可用工具、路径与服务策略不同。

延伸阅读 Linux
讲清楚了吗?

文件与权限

1个问题
14 为什么用户有时能删除不可读文件,却无法删除自己拥有的文件? 中级 常见 查看答案 ▾ 收起 ▴

读取内容时,系统针对文件本身授权;删除名称时,系统修改的是父目录。移除目录项通常因此需要父目录的写入和搜索权限,而不要求文件可读。共享临时目录上的 sticky bit 会增加所有权规则,挂载选项或强制访问控制还可能继续限制。我会结合进程的有效凭据检查路径的每一级目录,并查看 ACL 与策略拒绝记录。仅凭文件所有权,无法判断能否修改所在目录。

延伸阅读 Linux
讲清楚了吗?

文件与存储

1个问题
15 为什么 df 可能报告文件系统已满,而 du 找不到对应文件? 中级 常见 查看答案 ▾ 收起 ▴

du 遍历仍可从目录项到达的对象,并累计它们占用的块;df 报告整个文件系统的分配情况。如果进程在最后一个目录项被删除后仍保持文件打开,inode 与数据会一直分配到最后一个打开文件描述关闭,但 du 已无法通过名称找到它。我会先确认两个命令针对同一挂载点,再检查已删除但仍打开的文件并定位所属服务。安全修复通常是让该服务关闭或重新打开文件,而不是盲目操作描述符。

延伸阅读 Linux
讲清楚了吗?

进程生命周期

1个问题
16 怎样设计可靠的 Linux 服务关闭流程? 高级 常见 查看答案 ▾ 收起 ▴

我会为关闭流程指定唯一所有者和可捕获的停止信号,通常是 SIGTERM。服务先停止接收新工作,再按业务语义取消或排空操作,把终止信号转发给子进程,关闭描述符,并在总截止时间前退出。监督进程等待并记录真实退出状态。超时后,它先收集有效诊断,再升级到 SIGKILL。我会测试启动中、请求处理中、依赖失败和重复信号下的关闭。PID 消失只证明进程终止,不能证明事务已经提交或租约已经释放。

延伸阅读 Linux
讲清楚了吗?

Git 数据模型

2个问题
17 Git 的 blob、tree、commit 与引用如何组合? 中级 常见 查看答案 ▾ 收起 ▴

Blob 只保存文件字节,不含路径或文件名。Tree 为 blob 与子 tree 关联名称和模式,因此一个根 tree 就能描述项目快照。Commit 指向根 tree,列出父提交,并保存作者、提交者和消息元数据。分支是指向 commit 的可移动引用;HEAD 通常以符号方式指向当前检出分支。这种分离让相同内容可以复用,也让分支成为同一张共享图上的轻量名称。我会用 cat-file、ls-tree 和 for-each-ref 检查模型,不会直接编辑 .git 下的文件。

延伸阅读 Git 内部模型
讲清楚了吗?
18 Git 索引是什么?它与 HEAD 和工作树有何区别? 中级 常见 查看答案 ▾ 收起 ▴

HEAD 解析到当前已提交快照,索引描述下一候选快照,工作树则包含可编辑文件。Git add 会读取路径的当前内容,写成 blob 并放入索引;之后的编辑只留在工作树,直到再次 add。因此,git diff 显示未暂存变化,而 git diff —cached 显示索引相对 HEAD 的已暂存变化。冲突时,索引可以在 stage 1、2、3 中分别保存基点、ours 和 theirs。解决文件并再次 add 后,这些条目会被一个 stage 0 条目替换。

延伸阅读 Git 内部模型
讲清楚了吗?

历史变换

1个问题
19 合并与变基在结构上有什么区别? 中级 常见 查看答案 ▾ 收起 ▴

真正的合并会根据合并基点组合两个端点的变化,再创建拥有多个父提交的 commit。已有提交保持身份,图中也明确记录开发线的汇合点。变基则把某分支独有的提交重新应用到新基点。父提交标识属于 commit 内容,所以即使最终文件相同,替代提交通常也会获得新标识。除非书面策略允许重写,我会对共享历史使用合并,并只在发布前用变基整理私有提交。Force-with-lease 是条件式引用更新,不是团队授权。

延伸阅读 Git 内部模型
讲清楚了吗?

故障恢复

1个问题
20 误执行 reset 后怎样恢复提交?Reflog 有哪些限制? 高级 常见 查看答案 ▾ 收起 ▴

我会先停止修改仓库,再带日期查看 git reflog,并根据操作、时间、tree 和父链找出 reset 前的 commit。确认完整对象标识后,我先在该位置创建救援分支,再决定是否执行 reset、cherry-pick 或 merge。Reflog 只属于本地仓库,其他克隆未必有相同条目;条目过期与垃圾回收最终可能删除不可达对象。它也无法恢复 Git 从未存储的工作树字节。重要历史应依靠受保护的远端引用或独立备份,不能假定固定九十天的恢复窗口。

延伸阅读 Git 内部模型
讲清楚了吗?

文本与区域设置

1个问题
21 国际化、本地化与区域设置有什么区别? 初级 常见 查看答案 ▾ 收起 ▴

国际化是把消息、格式规则和书写方向从业务逻辑中分离的软件设计。本地化为特定市场填充并验证这些输入;翻译只是其中一部分,还包括术语与版式审查。区域设置是运行时选择相关行为的一组约定,通常用包含语言、书写系统和地区的 BCP 47 标签表示。它不是用户位置,也不能决定货币或时区。我会分别建模这些值,并用确定策略把请求区域设置解析到产品实际部署的目录。

延伸阅读 国际化
讲清楚了吗?

数据与呈现

1个问题
22 为什么区域设置、货币和时区应是独立的格式化输入? 中级 常见 查看答案 ▾ 收起 ▴

这些值表达不同事实。区域设置控制分隔符与符号位置等呈现约定;货币属于订单或报价;时区来自用户或事件上下文。中文用户完全可能用欧元付款并查看巴黎时间,从一个值推断另一个会丢失正常状态。我会保存带货币代码的原始金额和含义明确的时间数据,只在展示边界格式化。服务端与客户端接收同一组解析结果,缓存键也包含所有真正改变渲染输出的维度。

延伸阅读 国际化
讲清楚了吗?

消息契约

1个问题
23 怎样设计并验证包含复数的消息目录? 中级 常见 查看答案 ▾ 收起 ▴

我会使用稳定的语义键,以及带具名、类型明确占位符的完整消息,不会按源语言顺序拼接翻译片段。复数消息通过消息运行时选择区域规则定义的类别,并始终提供 other;=0 这样的精确分支与 zero 类别不同。构建时要比较目录键集合、占位符名称和类型、复数变量及允许的富文本槽位。开发环境让缺键明显失败;生产环境可以执行短而确定的回退链,但要记录请求区域设置、命中目录和缺失键。

延伸阅读 国际化
讲清楚了吗?

双向界面

1个问题
24 除了设置 dir="rtl",正确的 RTL 支持还需要什么? 高级 偶尔 查看答案 ▾ 收起 ▴

根元素的 lang 与 dir 必须来自同一个已解析区域设置,布局则使用 CSS 逻辑属性,避免左右方向假设。姓名、URL 和订单号等动态片段可能与周围文本方向相反,因此要用 bdi 或等效机制隔离。图标镜像取决于语义:返回箭头可能要翻转,播放符号与品牌通常不应翻转。我会用真实 RTL 内容测试键盘与朗读顺序、复制、选择、焦点和辅助技术,因为镜像截图无法暴露所有双向边界缺陷。

延伸阅读 国际化
讲清楚了吗?

算法正确性

1个问题
25 怎样证明一个递归函数会终止? 中级 常见 查看答案 ▾ 收起 ▴

我会先定义接纳的输入域和所有基本情况,再选择一个良基度量,通常是剩余长度或区间宽度等非负整数。接着证明进入函数时度量有效,并且它会在每条递归边上严格减小,而不只是常见分支。由于该度量不可能无限下降,执行最终必然抵达边界。对于图,结构大小不足以证明终止,因为边可能形成环;因此我会在下降前标记节点身份,并把可达但尚未访问的有限节点集合用作度量。

延伸阅读 递归
讲清楚了吗?

复杂度分析

3个问题
26 为什么递归运行时间与调用深度是不同的量? 中级 常见 查看答案 ▾ 收起 ▴

运行时间取决于调用总数和每次调用的工作量,栈空间则取决于同时尚未结束的最大调用数。平衡树遍历会访问所有节点,因此耗时为 O(n),调用深度只有 O(log n)。链状树仍耗时 O(n),但深度升至 O(n)。朴素 Fibonacci 的深度是线性的,总调用数却因分支重复计算重叠状态而呈指数增长。我会用调用树分析工作量,用最长的根到叶路径分析深度,再单独计算其他存储。

延伸阅读 递归
讲清楚了吗?
30 怎样从陌生代码中推导复杂度界限? 初级 常见 查看答案 ▾ 收起 ▴

我先定义每个独立输入维度,并选择有意义的操作作为计数单元。随后追踪顺序阶段、循环、递归、分配,以及自身成本依赖输入的调用。顺序成本相加,完整遍历的嵌套通常相乘,按固定比例缩小问题通常表示对数工作;但我会检查索引如何移动,不会只凭缩进判断。我分别推导时间与峰值辅助空间,简化主导项,并标明相关情形与假设。最后用边界、代表性和对抗性输入的操作计数或翻倍比值检验模型。

延伸阅读 算法复杂度
讲清楚了吗?
31 最坏情况、期望复杂度与摊还复杂度有什么区别? 中级 常见 查看答案 ▾ 收起 ▴

最坏情况复杂度限制某个规模下成本最高的有效输入,适合截止时间或恶意输入。期望复杂度依赖明确的概率或数据结构假设,例如随机化哈希;没有假设时,结论并不完整。摊还复杂度则限制任意相关操作序列的总成本,再分摊给各次操作,不需要概率分布。因此,动态数组追加在扩容时最坏可达 O(n),跨多次追加的摊还成本却是 O(1)。我会报告真正影响产品限制的情形,而不是脱离上下文只给一个标签。

延伸阅读 算法复杂度
讲清楚了吗?

遍历设计

1个问题
27 怎样把递归深度优先遍历改成显式栈,同时保持行为不变? 中级 偶尔 查看答案 ▾ 收起 ▴

我先确定每个递归栈帧保存的内容,包括节点、局部累加器、下一个子节点,以及子调用返回后的工作。前序遍历可以立即处理节点,并从右向左压入子节点,让后进先出栈保持从左到右的访问顺序。后序遍历需要显式阶段或下一个子节点索引来表示返回位置。我还会保持重复节点处理、错误时机和部分结果规则,为显式栈设置应用级限制,并先在小型分支树、链、环和失败场景上对比两个版本。

延伸阅读 递归
讲清楚了吗?

故障诊断

5个问题
28 递归函数通过了测试,却在生产环境遇到 RecursionError。你会怎样诊断和修复? 高级 常见 查看答案 ▾ 收起 ▴

我会捕获输入形状和有界栈帧追踪,再判断深度来自有效长链、环,还是某条没有取得进展的分支。随后写出终止度量,并检查每条递归边。提高递归限制不是默认修复,因为它只改变防护值,既不减少栈帧,也不能证明终止。我会按业务需要增加环检测和资源限制,并对大型或外部输入把线性深度递归改成显式栈。回归测试要覆盖准确边界、更深的链、自环和遍历顺序。

延伸阅读 递归
讲清楚了吗?
47 次缺页、主缺页、非法访问与 OOM 有什么区别? 中级 常见 查看答案 ▾ 收起 ▴

次缺页需要内核处理,但按照操作系统的统计定义,不需要为缺失页执行存储 I/O;主缺页则需要 I/O。两者都可能恢复并重试指令。非法访问表示该地址没有允许当前操作的映射;Linux 通常以带故障元数据的 SIGSEGV 或 SIGBUS 报告。OOM 是资源策略结果:在系统或 cgroup 约束下,回收仍无法满足请求时,内核可能终止选中的进程。我会保留准确计数器、信号、异常、cgroup 事件和故障附近映射,不会把所有情况都称作「内存不足」。

延伸阅读 虚拟内存
讲清楚了吗?
59 怎样在不削弱校验的情况下诊断 TLS 连接失败? 中级 常见 查看答案 ▾ 收起 ▴

我会先区分 DNS 解析、传输连接、TLS 协商、证书路径构建、主机名校验和应用协议,并记录请求 authority、已选地址、SNI、ALPN 结果、安全错误码及阶段耗时。遇到证书错误时,我会从干净客户端环境检查实际提供的叶证书与中间证书、已配置信任锚、参考主机名、SAN 条目、有效时间和端点时钟。测试必须覆盖真实代理路径,不能只测源站。我不会把 rejectUnauthorized 设为 false,因为这样既会隐藏证据,也可能把凭据发给冒充者。

延伸阅读 TLS 连接
讲清楚了吗?
71 NXDOMAIN、NODATA、SERVFAIL 与超时在运维上有何区别? 中级 常见 查看答案 ▾ 收起 ▴

NXDOMAIN 是名称不存在的权威声明。NODATA 是成功响应,表示现有名称没有请求类型的记录,因此查询其他类型仍可能成功。SERVFAIL 表示解析器无法生成可用答案,例如所有权威服务器都失败,或 DNSSEC 验证结果错误。超时只表示调用方等待时间内没有收到响应。我只按推导出的生存时间否定缓存权威不存在,并把暂时性故障保留为不同状态;仅在同一有界截止时间内跨合适服务器重试。以上结果都不能证明应用端口已关闭。

延伸阅读 DNS 解析
讲清楚了吗?
72 两台机器查询同一主机名却得到不同 DNS 答案时,应怎样诊断? 高级 偶尔 查看答案 ▾ 收起 ▴

我会先让两个问题真正可比:绝对名称、记录类型、类别、查找 API、递归解析器、网络或租户视图以及查询时间都要一致。随后记录响应码、答案、权威部分、TTL 与 DNSSEC 状态,再直接查询目标递归解析器。剩余 TTL 不同可能只是缓存年龄不同;数据不同则可能来自分割视图、地理策略、分阶段发布、过期数据供应或权威副本不一致。我还会向父委派和每台权威服务器查询 NS、SOA、别名、A 与 AAAA。最后要把解析与连接复用分开,因为现有连接池可能一直使用旧地址。

延伸阅读 DNS 解析
讲清楚了吗?

渐近记号

1个问题
29 大 O、大 Omega 与大 Theta 有什么区别?紧确界为什么重要? 初级 常见 查看答案 ▾ 收起 ▴

大 O 表示渐近上界,大 Omega 表示下界,大 Theta 表示超过某个阈值后,上下界在常数因子范围内匹配。线性函数从技术上也属于 O(n²),因此只有大 O 的结论可能正确却没有信息量。能证明紧确增长时,我会优先使用 Theta,并说明结论针对最坏、期望还是摊还情形。我还会定义输入变量与成本模型。记号用于比较增长,不会给出毫秒数,也不会消除在支持输入规模下仍然重要的常数。

延伸阅读 算法复杂度
讲清楚了吗?

工程取舍

1个问题
32 常数空间的二次重复项检查与线性空间、期望线性时间的检查之间应如何选择? 中级 常见 查看答案 ▾ 收起 ▴

我会先确认最大与典型元素数量、内存预算、延迟目标,以及键是否可能来自对抗性输入。成对比较的最坏时间为 Θ(n²),辅助空间为 Θ(1);在哈希约定下,集合的期望时间与空间都是 Θ(n)。如果输入很小且有硬上限,简单扫描可能凭常数和较少分配获胜;输入会增长时,集合通常更容易扩展。我会在预期交叉点附近使用代表性键做基准测试,检查无重复项的最坏路径,限制可接受基数,并记录假设,以便流量变化后重新评估。

延伸阅读 算法复杂度
讲清楚了吗?

算法选择

1个问题
33 什么时候应扫描无序数据,而不是先排序或建立索引? 初级 常见 查看答案 ▾ 收起 ▴

我会先看完整的操作组合。只有一次查询、集合较小、数据频繁变化,或谓词不符合现有顺序时,扫描通常更合适;它的前置条件很弱,首次匹配后还能停止。排序会预付 O(n log n) 的比较成本,但可支持之后的大量有序查询或范围查询。哈希索引适合反复进行精确键查找,却占用额外内存,也要随数据更新。我会一起比较构建、查询、修改和新鲜度要求,在最简单的正确设计完成后,再用代表性数据测量。

延伸阅读 排序与查找
讲清楚了吗?

顺序契约

1个问题
34 比较函数必须保证什么?稳定排序还会提供什么额外保证? 中级 常见 查看答案 ▾ 收起 ▴

比较函数用负数、0 或正数表示靠前、顺序等价或靠后,而且答案必须一致:与自身比较时相等,交换参数会翻转符号,顺序还要满足传递性。稳定排序会保留比较相等的不同记录在输入中的相对顺序,但不会生成业务上的同值排序条件,也不能让无序输入变得确定。如果分页或可重复输出需要全序,我会增加一致的次级键,通常最后使用唯一标识。排序前还要定义空值、字段缺失、区域规则和规范化行为。

延伸阅读 排序与查找
讲清楚了吗?

查找不变量

1个问题
35 下界二分查找怎样工作?如何说明它是正确的? 中级 常见 查看答案 ▾ 收起 ▴

我使用半开区间 [low, high)。low 之前的每个索引都已知小于目标,high 及其后的位置都已知大于或等于目标。若中间键太小,就把 low 设为 middle 加 1;否则把 high 设为 middle,因为该位置仍可能是答案。两个分支都会缩小区间。low 与 high 相等时,两条不变量在第一处不小于目标的键上相接;目标大于全部键时,该位置就是数组后的有效插入点。排序与查找必须采用相同键顺序。

延伸阅读 排序与查找
讲清楚了吗?

范围查询

1个问题
36 怎样返回有序键位于指定范围内的全部记录? 中级 偶尔 查看答案 ▾ 收起 ▴

我会先定义端点语义。对于半开范围 [minimum, maximum),下界查找执行两次:先找第一处不小于 minimum 的键,再找第一处不小于 maximum 的键,最后截取两者之间的切片。如果 maximum 也包含在结果中,第二次应使用上界,也就是第一处大于 maximum 的键。这样能处理边界上的重复键,而不扫描无关值。我会测试空输入、相等端点、数据前后的边界,以及两端连续重复项;查询期间有序快照还必须遵守同一比较策略。

延伸阅读 排序与查找
讲清楚了吗?

HTTP 约定

1个问题
37 安全 HTTP 方法与幂等方法有什么区别? 初级 常见 查看答案 ▾ 收起 ▴

安全方法要求只读语义:客户端没有请求改变资源状态,但日志或指标等附带影响仍可发生。幂等方法可以改变状态,不过重复同一请求的预期效果与只发送一次相同。所有安全方法都幂等,但 DELETE 和 PUT 幂等却不安全。幂等性不要求响应完全相同;首次 PUT 可以返回 201,重复请求则返回 204。我会用这些属性设计重试、测试和中间节点行为,再明确补充应用层更窄的保证。

延伸阅读 HTTP 语义
讲清楚了吗?

重试与故障

1个问题
38 写请求在收到响应前超时时,客户端应如何处理? 中级 常见 查看答案 ▾ 收起 ▴

我会把结果保留为未知,因为超时表示没有按期取得进展,不表示事务已经回滚。请求可能尚未到达、仍在运行,也可能已经提交而响应丢失。只有当方法和应用约定允许安全重放、请求体可以重现,而且重试仍在尝试次数与总截止时间预算内时,我才会自动重试。非幂等操作需要稳定且由服务端强制执行的幂等键,或通过操作标识符查询结果。退避与抖动能保护容量,却不能解决重复副作用。

延伸阅读 HTTP 语义
讲清楚了吗?

缓存与验证器

1个问题
39 请解释收到 304 Not Modified 的条件式 GET。 初级 常见 查看答案 ▾ 收起 ▴

缓存先保存成功 GET 的表示及其验证器,通常是 ETag。需要验证后才能复用时,它会用 If-None-Match 发送该标签。如果选定的当前表示仍然匹配,服务端就返回不带表示内容的 304。缓存保留已存内容,用验证响应允许的元数据更新它,再提供组合后的结果。标签不匹配时,服务端通常返回带有新表示的 200。因此,304 不是空的 200,没有已存响应的客户端也不能把它当作内容使用。

延伸阅读 HTTP 语义
讲清楚了吗?

协议边界

1个问题
40 为什么 HTTP 消息边界不同于连接边界? 中级 偶尔 查看答案 ▾ 收起 ▴

连接是传输会话,请求与响应则是由它承载的协议消息。HTTP/1.1 可以在一个持久连接上依次发送多次交互,因此要用内容长度、传输编码、方法和状态规则划分消息,而不能等待 EOF。HTTP/2 在一个连接上承载多个并发流,流故障的作用域小于连接故障。因此,关闭或更换连接不能说明应用是否提交。我会在日志与重试决策中区分连接、流、请求尝试和幂等标识符。

延伸阅读 HTTP 语义
讲清楚了吗?

数据结构选择

1个问题
41 怎样在数组与链表之间选择? 初级 常见 查看答案 ▾ 收起 ▴

我会先确认实际操作及其输入。数组支持按索引常数时间访问、紧凑遍历;动态数组的追加摊还为常数时间,但中部插入要移动后缀。链表按数字位置访问需要线性遍历,不过在所需节点或前驱已经确定时,插入与删除只需固定数量的链接更新。我还会计算内存:每个节点都带链接且通常单独分配,数组则可能保留空余容量。默认先使用标准动态数组,只有工作负载确实需要时,才对其他表示进行基准测试。

延伸阅读 数组与链表
讲清楚了吗?

复杂度契约

2个问题
42 为什么「链表插入是 O(1)」并不完整? 中级 常见 查看答案 ▾ 收起 ▴

常数时间只描述位置确定后的指针改链。如果 API 接收索引或元素值,普通链表通常要从端点开始寻找前驱,这一步是 O(n)。在单向链表中,即使目标节点已知,删除时仍可能需要前驱。我会明确写出前置条件,例如「在这个已知节点后插入」,或者「移除这个已知双向节点」。如果另一个映射提供节点句柄,还要计入它的内存与一致性成本。复杂度应覆盖调用方的完整操作,不能只描述最后几次赋值。

延伸阅读 数组与链表
讲清楚了吗?
62 为什么哈希表查找是预期 O(1),而不是保证 O(1)? 中级 常见 查看答案 ▾ 收起 ▴

预期常数时间要求哈希分布合适、负载受控,而且相等比较成本合理。如果大量键进入同一个桶或探测簇,查找就要检查更多候选项,成本可能接近 O(n)。除非哈希已缓存,对变长键求哈希的成本也随检查的输入增长。恶意客户端还可能利用可预测的弱哈希制造集中冲突。我会明确这些假设,限制不可信键长度与集合容量,使用运行时加固的映射;尾延迟重要时,还要测量代表性与对抗性键分布。

延伸阅读 哈希表
讲清楚了吗?

增长与延迟

2个问题
43 动态数组的一次扩容是 O(n),为什么追加仍可摊还为 O(1)? 中级 常见 查看答案 ▾ 收起 ▴

动态数组会保留空余容量,所以多数追加只写入一个未用槽位。容量耗尽时,它分配更大的底层区域并移动已有元素,因此那一次追加是 O(n)。若容量按几何比例增长,例如每次翻倍,那么长操作序列中的移动次数构成几何级数,总量与成功追加次数成正比。这得到的是摊还常数成本,不是单次最坏延迟恒定。如果某次慢追加会违反截止时间,我会预留已知容量,或选择有界、分块结构,并测量相应的内存取舍。

延伸阅读 数组与链表
讲清楚了吗?
63 哈希表扩容时发生什么,为什么插入仍是摊还 O(1)? 中级 常见 查看答案 ▾ 收起 ▴

负载超过实现阈值后,表会分配更大存储并移动活动条目。它不能按原索引直接复制桶,因为索引缩减依赖容量;增长后,同一个完整哈希值可能选中另一个桶。这次扩容具有 O(n) 成本,也可能造成延迟与内存峰值。不过,采用几何增长时,扩容不会频繁发生,长插入序列中的移动总量仍与插入条目数成正比。因此,整个序列的插入成本摊还为 O(1),但触发增长的那一次插入仍是线性的。

延伸阅读 哈希表
讲清楚了吗?

内存行为

1个问题
44 缓存局部性与内存开销怎样影响数组和链表的选择? 高级 偶尔 查看答案 ▾ 收起 ▴

连续数组槽位通常彼此相邻,因此一次缓存行读取与硬件预取可以服务接下来的多个访问。单独分配的链表节点带有一或两个链接,而且只有读完当前节点才能知道下一个地址;即使同为 O(n),遍历仍可能承担更多分配与缓存成本。我不会给出通用速度比例,因为元素形状、分配器、运行时和硬件都会改变结果。我会先按槽位大小、空余容量、链接字段、对象头与对齐建立字节模型,再用堆剖析和代表性遍历基准确认。

延伸阅读 数组与链表
讲清楚了吗?

地址转换

1个问题
45 虚拟内存在程序地址与物理 RAM 之间增加了什么? 中级 常见 查看答案 ▾ 收起 ▴

程序使用所属进程地址空间中的虚拟地址。处理器先检查缓存的地址转换,或者遍历页表;页表把虚拟页映射到物理页框,同时携带访问权限。如果没有可用的现存页表项,缺页会把控制交给内核。内核可能提供匿名页、找到已缓存文件页、恢复换出数据、执行写时复制,或者拒绝访问。这层机制提供重定位、保护、稀疏预留和受控共享,却不保证每个映射字节都已驻留,也不表示地址空间容量等于可用 RAM。

延伸阅读 虚拟内存
讲清楚了吗?

内存诊断

1个问题
46 怎样判断 RSS 上升是否表示应用内存泄漏? 中级 常见 查看答案 ▾ 收起 ▴

我会先统一观察范围:同一进程代次、cgroup、命名空间和工作负载区间。随后在一条时间线上比较虚拟映射、RSS、比例集大小、私有脏页、分配器或堆分析、缓存所有权与 cgroup 记账。RSS 上升可能来自存活对象、分配器保留待复用的 arena、文件缓存、首次触页或写时复制,因此单次快照不能证明泄漏。我会降低负载或设置可控生命周期边界,观察哪些所有权消失,以及内核在压力下能回收什么。修复应针对保留数据的所有者,而不是最大的概要数字。

延伸阅读 虚拟内存
讲清楚了吗?

进程内存

1个问题
48 有写时复制时,为什么 fork 后的内存用量仍可能快速上升? 高级 偶尔 查看答案 ▾ 收起 ▴

写时复制避免在 fork 时立即复制全部私有页。父子进程最初可以映射相同物理后备,并通过会在后续写入时触发故障的权限保持私有语义。任一进程修改页面后,内核都必须保留各自内容,因此共享程度下降,物理内存汇总记账可能上升。若父子双方弄脏大型驻留堆中的许多页,成本会很高;运行时维护也可能写入应用原以为会保持共享的页。我会测量 fork 工作负载前后的比例内存与私有内存,纳入 cgroup 记账;子进程不需要继承运行时状态时,则使用受支持的启动并立即执行路径。

延伸阅读 虚拟内存
讲清楚了吗?

Shell 解析

1个问题
49 怎样从 Shell 源文本推导外部程序最终收到的参数? 初级 常见 查看答案 ▾ 收起 ▴

我会把解析与执行分开。先识别运算符、引用上下文和 Shell 单词,再追踪参数展开、算术展开与命令替换;适用时继续追踪单词拆分和路径名展开,最后处理引号删除。结果是参数向量,而不是原始命令行字符串。我会把每个最终参数单独写出,并保留空参数。遇到不确定代码时,我会暂时用一个打印参数数量和引用后参数的函数代替目标命令,再在受控目录中测试空格、通配符、换行与前导连字符。

延伸阅读 Shell 基础
讲清楚了吗?

参数边界

1个问题
50 为什么 Bash 函数通常要用带双引号的 "$@" 转发参数? 初级 常见 查看答案 ▾ 收起 ▴

位于双引号内时,”$@” 会把每个位置参数展开成独立单词,因此能保留调用方的参数数量、单个参数内的空格与空参数。未引用的 $@ 会让值继续参与单词拆分和路径名展开,”$*” 则使用 IFS 的第一个字符把全部参数连接成一个单词。我会至少使用空参数、带空格的值、字面量星号和前导连字符值验证转发包装器。被包装命令仍可能需要选项终止符,因为引用不会停止选项解析。

延伸阅读 Shell 基础
讲清楚了吗?

安全自动化

1个问题
52 怎样审查一条会删除文件的生成 Shell 命令? 中级 常见 查看答案 ▾ 收起 ▴

我会先检查权限与恢复,而不只检查引用。首先确认每项输入由谁控制,根据契约只接受最窄的标识或路径,并拒绝空目标、根目录、相对路径与范围外目标。随后推导准确操作数数组,确认选项终止位置,再检查通配符、符号链接、挂载点与竞争行为。我会在临时目录树中,用空格、通配符和前导连字符名称运行不修改数据的选择逻辑。无人值守运行前,还要具备有界删除范围、有效诊断、保留的失败状态、幂等清理路径,以及经过测试的恢复或回滚方法。

延伸阅读 Shell 基础
讲清楚了吗?

操作系统并发

1个问题
53 如何为并发工作选择进程或线程? 中级 常见 查看答案 ▾ 收起 ▴

我会先确定所需边界。进程通常拥有独立虚拟地址空间、身份、资源表和可单独观察的退出状态,因此适合隔离故障、分离权限或独立部署。线程共享同一进程,可以较低传输成本通过共享内存通信,但也会共同承受内存破坏与资源压力。随后我会分析运行时规则、序列化或加锁成本、启动速率、最大并发量与关闭流程,并根据实测工作负载和所有权需求选择,不会预设线程总是更快。

延伸阅读 进程与线程
讲清楚了吗?

同步

1个问题
54 为什么把计数器改成原子变量,仍不足以让共享操作具备线程安全性? 中级 常见 查看答案 ▾ 收起 ▴

原子计数器只保护指定的计数操作。一次业务状态转换还可能检查容量、预留元素、更新余额并追加账本记录,其他线程能够在这些分别原子的步骤之间插入,观察或产生无效组合。我会先写出不变量,找出参与其中的每个状态字段与访问路径,再用同一项所有权规则保护完整转换。实现可以采用互斥锁、原子比较交换协议或单一所有者队列。测试用于覆盖不利交错,但同步论证才真正建立正确性。

延伸阅读 进程与线程
讲清楚了吗?

生命周期与关闭

1个问题
55 有界工作池应定义怎样的生命周期契约? 中级 常见 查看答案 ▾ 收起 ▴

工作池需要明确工作单元硬上限、有界准入与溢出策略。所有者要定义创建失败、结果交付、工作单元崩溃、超时、取消,以及排队任务能否放弃。优雅关闭先停止准入、请求取消、允许安全的进行中工作结束、关闭通道,再在截止时间内等待所有工作单元,必要时升级终止手段。等待只能观察终止,本身不会请求终止。我还会规定结果顺序与部分失败语义,并测试工作单元阻塞、启动、结束和报错时的关闭行为。

延伸阅读 进程与线程
讲清楚了吗?

并发诊断

1个问题
56 如何调查间歇出现的进程或线程并发故障? 高级 偶尔 查看答案 ▾ 收起 ▴

我会先写明遭到违反的不变量,再用单调时间戳、进程与线程身份、消息标识、锁等待、取消请求和退出事件建立时间线。随后枚举访问相关状态的所有路径,标出本应为每组冲突访问建立顺序的先发生边。接着在边界强制制造消息延迟、创建失败、工作单元崩溃与取消。竞态检测器、线程消毒器和调度追踪可以暴露证据,但只覆盖实际执行路径。复现一条失败调度后,我会缩减它,并保留为确定性回归测试。

延伸阅读 进程与线程
讲清楚了吗?

连接安全

1个问题
57 为什么证书链校验与主机名校验是两项独立的 TLS 检查? 中级 常见 查看答案 ▾ 收起 ▴

证书链校验会检查签名和证书约束,判断所提供叶证书能否到达客户端预先接受的信任锚。主机名校验则判断叶证书是否覆盖参考服务身份,该身份通常来自原始 URL 或配置。即使证书链完全受信,payments.example 的证书用于 login.example 时仍必须失败;证书包含 login.example,但只能连接到未知根时也必须失败。我会让原始名称经过 DNS 与路由后保持不变,把它同时用于 SNI 和校验,并在发送凭据前要求两项检查都成功。

延伸阅读 TLS 连接
讲清楚了吗?

协议机制

1个问题
58 TLS 1.3 握手如何结合密钥协商与服务器认证? 中级 常见 查看答案 ▾ 收起 ▴

客户端和服务器交换临时 Diffie-Hellman 公开份额,再各自派生相同的共同输入。密钥协商本身不是认证,因为攻击者可以分别与两个端点协商不同秘密。因此,服务器会发送证书链和覆盖握手记录的 CertificateVerify 签名,证明自己持有认证私钥,并把协商绑定到该私钥。随后,Finished 值使用派生秘密认证握手记录。密钥计划会分别派生握手密钥和两个方向的应用流量密钥;证书签名密钥不会用于加密大量应用字节。

延伸阅读 TLS 连接
讲清楚了吗?

会话生命周期

1个问题
60 TLS 会话恢复和 0-RTT 早期数据需要哪些安全决策? 高级 偶尔 查看答案 ▾ 收起 ▴

会话票据是恢复凭据,因此我会限制生命周期、轮换保护密钥,并在不同安全域之间隔离这些密钥。TLS 1.3 有前向保密要求时,我会优先让恢复过程包含新的临时协商。0-RTT 必须单独判断:新握手完成前发送的早期数据可能被重放。除非完整应用操作可安全重复,否则应保持关闭。名义上的读取仍可能消耗令牌、写入审计事件或触发昂贵工作,因此只有 HTTP 方法标签不足以证明操作安全。

延伸阅读 TLS 连接
讲清楚了吗?

哈希表机制

1个问题
61 两个键发生冲突时,哈希表怎样保持正确? 中级 常见 查看答案 ▾ 收起 ▴

哈希值与桶索引只会缩小候选集合,不能确定键标识。拉链表把两个条目都保留在选中的桶里,开放寻址表则按共享探测规则寻找其他槽位。查找会重复同一路径,并把每个候选键与请求键比较。相等键必须产生相同哈希值,不相等键仍可冲突;只有相等检查成功后,插入才能更新已有值。我会用必定冲突但不相等的键测试更新、未命中与删除,并覆盖两种插入顺序。

延伸阅读 哈希表
讲清楚了吗?

键设计

1个问题
64 怎样为哈希表设计安全的复合键? 高级 偶尔 查看答案 ▾ 收起 ▴

我会先定义业务相等关系:哪些字段表示同一实体,并明确类型、大小写、Unicode 归一化和缺失值规则。哈希或规范表示必须使用完全相同的规则,而且在存储期间保持稳定。字段可能包含分隔符时,直接连接并不安全,因此我更倾向值键类型或有明确规范的长度前缀编码。插入、查找与删除都调用同一个规范化函数。面对公开输入,还要限制字段长度与集合大小,并测试重建的相等键、类似分隔符的值、归一化变体、修改和刻意冲突。

延伸阅读 哈希表
讲清楚了吗?

图建模

1个问题
65 怎样判断数据应按树还是按图处理? 中级 常见 查看答案 ▾ 收起 ▴

我会先看不变量,而不是字段名称。有根树只有一个根,其他节点恰好各有一个父节点,每个节点都能从根到达,而且不存在环。一般图数据则可能有共享目标、多个父节点、环或断开的顶点。我会确认边的含义、是否有向,以及哪个稳定键定义顶点标识。如果外部 API 只提供 children 字段,我仍会验证父节点唯一性与无环性。缺少这些保证时,应使用带已访问状态的图遍历,而不能信任树形序列化外观。

延伸阅读 树与图
讲清楚了吗?

遍历策略

1个问题
66 DFS 与 BFS 有何区别,分别应在什么场景选择? 中级 常见 查看答案 ▾ 收起 ▴

DFS 使用显式栈或递归调用栈,会先沿一个分支前进,再返回处理其他选择,适合递归求值、回溯、发现连通分量,以及需要完成顺序的算法。BFS 使用队列,按边数逐层扩展顶点;当每条边成本相等时,这个分层不变量保证第一次发现得到最短路径。一般图上的两种算法都需要按稳定标识维护已访问状态,配合邻接表时都是 O(V + E)。还要比较内存形态:BFS 可能保留很宽的一层,递归 DFS 则可能在深链上耗尽运行时栈。

延伸阅读 树与图
讲清楚了吗?

环检测

1个问题
67 为什么已访问集合不足以检测有向环? 高级 常见 查看答案 ▾ 收起 ▴

已访问状态只能说明顶点以前是否出现,不能说明此前遍历是否仍在当前路径上。有向 DFS 因此区分未发现、活跃和已完成顶点。指向活跃顶点的边是反向边,可以证明存在环;指向已完成顶点的边可能只是汇入已经探索过的部分。我会为活跃顶点保留父节点,让错误能够报告具体环路径。在无向图中,返回直接父节点的边是预期行为,因此检测条件必须考虑方向,不能原样复用有向图判断。

延伸阅读 树与图
讲清楚了吗?

表示与复杂度

1个问题
68 图的表示形式怎样影响遍历成本与正确性? 中级 偶尔 查看答案 ▾ 收起 ▴

使用邻接表时,在通常的集合操作假设下,DFS 或 BFS 会处理每个可达顶点一次,并检查每条已存储出边一次,因此工作量为 O(V + E)。邻接矩阵会为每个已处理顶点扫描 V 个潜在邻居,所以即使图很稀疏,完整遍历也要执行 O(V²) 次单元格检查。表示形式还携带正确性契约:缺失映射键可能表示叶子或非法引用;无向边通常要在两个方向存储;邻居顺序会选择一种有效遍历或最短路径结果。讨论复杂度前,应先定义这些规则与稳定顶点标识。

延伸阅读 树与图
讲清楚了吗?

解析路径

1个问题
69 说明应用的一次 DNS 缓存未命中查询怎样到达权威答案。 中级 常见 查看答案 ▾ 收起 ▴

应用通常先请求存根解析器,由它把名称和类型转交递归解析器。缓存未命中时,递归解析器从已知根服务器地址开始;根响应把它转介到相关顶级域服务器,顶级域响应再把它转介到子区域的权威服务器。解析器查询其中一台服务器,在跳数上限内跟随 CNAME 链,按剩余 TTL 缓存所得记录集,再把候选地址返回应用。转介、超时和否定答案都属于解析阶段,不是与应用服务建立的传输连接。

延伸阅读 DNS 解析
讲清楚了吗?

缓存与变更

1个问题
70 为什么 DNS TTL 不能精确决定所有客户端切换地址的时刻? 中级 常见 查看答案 ▾ 收起 ▴

TTL 限制的是某个缓存收到记录后通常还能复用多久。各缓存取得答案的时间不同,所以过期时刻也不同;应用还可能使用独立缓存策略,已经建立的套接字或连接池不会仅因记录过期就重新查询 DNS。迁移时,我会提前降低 TTL,等待旧 TTL 完整经过,让新旧端点在重叠期都保持健康,并在退役旧端点前观察流量。我还会检查别名以及 A、AAAA 数据,因为每个依赖记录集都有自己的生存时间。

延伸阅读 DNS 解析
讲清楚了吗?

文本表示

1个问题
73 字节、UTF-16 代码单元、码点与字素簇有什么区别? 初级 常见 查看答案 ▾ 收起 ▴

字节属于 UTF-8 等编码后的表示。UTF-16 代码单元是 16 位存储单位;JavaScript 的 length 与切片按它工作,补充平面码点需要一对代理项。码点是 Unicode 代码空间中的编号位置,但代理项码点不属于标量值。扩展字素簇则是分段规则视为一个用户感知字符的序列,例如基础字母加重音,或由连接符组成的家庭 emoji。我会按操作选择单位:协议容量按字节,Unicode 值检查按码点,光标移动与可见限制按字素。

延伸阅读 Unicode 文本
讲清楚了吗?

编码边界

1个问题
74 怎样安全解码按网络分块到达的 UTF-8? 中级 常见 查看答案 ▾ 收起 ▴

我会从协议取得编码,而不是根据字节猜测。多字节序列可能在一个分块中开始、下一个分块中结束,因此要复用同一个流式解码器;独立解码各块会错误替换或拒绝有效文本。流结束时还要完成解码,以检测待处理的不完整序列。对于标识符、签名数据或导入内容,我通常采用严格失败模式,并在策略允许时保留原始字节供诊断。线路大小限制在解码前按字节执行,面向用户的限制则在成功解码后另外按字素检查。

延伸阅读 Unicode 文本
讲清楚了吗?

规范化与相等

1个问题
75 文本应在什么时候规范化?NFC 与 NFKC 会怎样改变策略? 中级 常见 查看答案 ▾ 收起 ▴

我只在相等契约明确要求的边界做规范化,并保留原始文本用于显示和审计。NFC 会让规范等价序列收敛,例如预组和的重音字母与其分解形式。NFKC 还会执行兼容映射,因此带圈数字或宽度变体可能与普通字符收敛。更宽的关系可以服务于明确规定的搜索键,却可能消除存储内容或标识符中的有意义差异。我会让每条写入与查询路径使用同一种指定形式,策略变化时给派生键升级版本并迁移旧数据,同时明确处理碰撞。

延伸阅读 Unicode 文本
讲清楚了吗?

比较契约

1个问题
76 为什么不能用区域敏感排序判断账户身份? 高级 偶尔 查看答案 ▾ 收起 ▴

排序器只为某个区域与选项组合定义顺序和等价关系。采用基础敏感度时,它可能忽略重音或大小写,因此比较结果为 0 并不能证明码点、字节或账户相同;运行时升级还可能改变区域数据。我只把排序用于展示顺序与产品定义的搜索,并明确指定区域和选项,再用稳定标识符作为最后的同值排序条件。身份、唯一性、权限和协议标记采用另一套由规范定义的比较键。我会按身份契约测试规范化、大小写、书写系统与碰撞,而不是借用显示行为。

延伸阅读 Unicode 文本
讲清楚了吗?

流契约

1个问题
77 命令为什么应当让标准输出与标准错误保持分离? 中级 常见 查看答案 ▾ 收起 ▴

标准输出是命令的结果通道,其他程序可以把它作为数据解析;标准错误独立承载诊断、警告与进度。如果脚本在解析器之前使用 2>&1,一条警告就可能变成伪记录、破坏 JSON 或改变校验和。我会在整条数据路径中分离两个通道,需要时把诊断重定向到专用日志,并把退出状态作为第三种信号保留下来。测试用的生产者会生成一条有效记录、一条警告和一个非零状态,从而真正验证消费者契约。

讲清楚了吗?

描述符路由

1个问题
79 为什么 `>file 2>&1` 与 `2>&1 >file` 的效果不同? 中级 常见 查看答案 ▾ 收起 ▴

Shell 从左到右应用重定向。>file 2>&1 先让标准输出指向文件,再把这个当前目标复制给标准错误,所以两个描述符都进入文件。2>&1 >file 则先让标准错误取得标准输出的旧目标,之后才把标准输出移到文件;标准错误会继续指向旧终端或管道。我把每个操作符当作一次描述符表更新,并用分别写入描述符 12 的不同标记进行测试。因此,重排词元会改变语义,不只是调整格式。

讲清楚了吗?

管道生命周期

1个问题
80 管道中的 EOF 与 SIGPIPE 由什么控制?管道为什么可能挂起? 高级 偶尔 查看答案 ▾ 收起 ▴

只有引用写入端的每个描述符都关闭后,读取方才会看到 EOF;表面上的生产者退出或缓冲区暂时为空都不够。继承的写入描述符副本因此可能让读取方永远等待。反过来,所有读取端都关闭后,继续写入通常会触发 SIGPIPE;如果忽略该信号,写入会以 EPIPE 失败。有限管道容量还会形成背压,缓冲区装满时生产者将阻塞。我会检查描述符所有权,关闭不用的端点,为操作设置总期限,并明确消费者提前关闭是否属于预期。

讲清楚了吗?

时间值建模

1个问题
81 时间点与民用日期时间有什么区别? 中级 常见 查看答案 ▾ 收起 ▴

时间点标识时间线上的一个位置,可以与其他时间点排序。民用日期时间则是一组日历与钟表字段,例如 2026-11-01 01:30;只有补充日历、时区或偏移以及切换策略后,它才能标识时间点。时钟空缺中的某些民用值没有候选时间点,重叠中的某些值则有两个。我会把事件时间戳、只有日期的值与尚未解析的日程建模为不同领域类型,再由拥有策略的边界负责转换。

延伸阅读 日期与时间
讲清楚了吗?

时区规则

2个问题
82 为什么 UTC 偏移不等于时区? 中级 常见 查看答案 ▾ 收起 ▴

像 -04:00 这样的偏移只说明与 UTC 的一个数值关系;配合完整本地字段时,它能够标识时间点。America/New_York 这样的 IANA 时区名提供随日期变化的地区规则,其中包括历史变化与已安装数据库中的未来规则。因此,每天 09:00 的会议需要保留时区,不能只保留创建时的偏移。已解析的传输时间戳仍应带明确偏移;日程数据则保留本地字段、时区标识符,以及处理空缺和重叠的策略。

延伸阅读 日期与时间
讲清楚了吗?
83 如何解析落在时区空缺或重叠中的本地输入? 高级 偶尔 查看答案 ▾ 收起 ▴

我会先验证日历字段并加载指定时区,再搜索能够准确投影回这些字段的时间点。零个候选项表示空缺,一个表示普通唯一时间,两个表示重叠。随后应用产品策略,而不是库默认值:对空缺选择拒绝或移动,对重叠选择较早、较晚或询问用户。在 Python 中,我会保留选定的 fold 或解析后时间点。测试使用真实切换点,同时断言本地往返与 UTC 结果,因为只附加 ZoneInfo 并不会拒绝不存在的字段。

延伸阅读 日期与时间
讲清楚了吗?

运算与时钟

1个问题
84 日历运算、经过时长与时钟选择如何相互影响? 中级 常见 查看答案 ▾ 收起 ▴

日历运算按照日历与时区规则保留字段:跨越向前拨钟时,明天中午可能只经过 23 小时。经过时间运算则保留时间线上的量,所以恰好 24 小时后可能显示为 13:00。我会在操作名称中写明选择,并在切换点与月末同时测试本地字段和时间戳差。进程内截止时间使用单调时钟,因为挂钟可能被校正。日志另行记录 UTC 时间点;单调时钟读数只相对于当前进程,不能充当通用时间戳。

延伸阅读 日期与时间
讲清楚了吗?

数值表示

1个问题
85 为什么 0.1 + 0.2 可能不等于 0.3?何时仍适合精确比较浮点数? 中级 常见 查看答案 ▾ 收起 ▴

Binary64 的精度有限,十分之一这样的分数在二进制中会无限循环。解析每个十进制数时都要选择附近的可表示值,加法还会再次舍入,因此存储的和可能不同于字面量 0.3 选择的值。这并不表示所有相等检查都有错。如果约定保证表示相同,例如安全整数、精确哨兵值或无损往返后的值,精确比较就很合适。对于独立计算的测量值,我会根据单位与算法误差预算推导绝对和相对容差,再单独处理 NaN 与无穷。

延伸阅读 浮点数运算
讲清楚了吗?

数值比较

1个问题
86 你会怎样设计和审查浮点数近似相等检查? 中级 常见 查看答案 ▾ 收起 ▴

我会先确认领域允许多少误差,以及算法本身会引入多少误差。绝对容差在零附近提供有意义的下限,相对容差则随较大操作数的量级缩放;常见规则是允许差值不超过两种界限中的较大者。我不会照搬 Number.EPSILON,因为它只描述 binary64 在一附近的间距。执行减法前,还要定义 NaN、无穷和带符号零的策略。测试应覆盖零、两个符号、普通与最大量级,以及每条界限内外的值。容差相等不具有传递性,因此也不能直接用作哈希键或排序等价关系。

延伸阅读 浮点数运算
讲清楚了吗?

范围与故障处理

1个问题
87 服务应怎样处理浮点溢出、下溢和非有限值? 中级 偶尔 查看答案 ▾ 收起 ▴

浮点溢出通常产生无穷而不是抛异常,无效算术可能产生 NaN,渐进下溢则会先降低相对精度,之后极小结果才变成零。因此,我会在领域边界用 Number.isFinite 这类不执行强制转换的谓词验证有限输入与结果。约定必须说明溢出时拒绝操作、饱和到上限,还是切换表示方式;静默接受无穷并不算策略。我会测试最大预期操作数、产生溢出的组合、正规数到次正规数的边界、带符号零和序列化。标准 JSON 没有 NaN 或无穷字面量,因此必须主动规定传输行为。

延伸阅读 浮点数运算
讲清楚了吗?

数值稳定性

1个问题
88 为什么求和顺序会改变浮点结果?怎样选择稳定方法? 高级 偶尔 查看答案 ▾ 收起 ▴

每次加法都会按照中间结果所在量级的间距舍入,因此浮点加法通常不满足结合律。小加数可能在大部分和旁边消失,两个接近的近似值相减则可能暴露灾难性消减。分块或并行归约会改变舍入树,末位结果也可能变化。我会检查输入量级和所需误差界限,再考虑成对求和、补偿求和、改写表达式或使用更高精度表示。测试要混合极大与极小值,并和高精度预言机比较。如果逐位可重现很重要,还要固定运算顺序、运行时行为和库实现。

延伸阅读 浮点数运算
讲清楚了吗?

文本校验

1个问题
89 怎样用正则表达式做校验,同时不把形状误认为含义? 初级 常见 查看答案 ▾ 收起 ▴

我会先写清词法契约:字符范围、分隔符、长度边界,以及是否必须匹配整个输入。在 JavaScript 中,我会确认整体匹配消费完整字符串,而不是把成功子串或 $ 当成绝对末尾。独立布尔校验器不使用 gy,因为它们会携带 lastIndex。形状通过后,再由普通代码或领域解析器检查含义,例如日历日期是否存在、标识符是否有对应实体。测试要覆盖有效输入、前后多余文本、末尾换行、边界长度,以及形状有效但语义无效的值。

延伸阅读 正则表达式
讲清楚了吗?

性能与安全

1个问题
90 什么会引发正则表达式的灾难性回溯?你会怎样控制风险? 中级 常见 查看答案 ▾ 收起 ▴

后续输入失败后,引擎重新尝试量词或分支属于正常回溯。若嵌套量词或重叠分支产生多种消费同一前缀的方式,风险就会升高;直到末尾才失败的长近似匹配尤其危险。我会消除有歧义的嵌套,提取公共前缀,在合适位置用分隔符感知字符类代替宽泛通配符,并在匹配前执行输入与重复边界。随后在可由测试框架终止的工作线程或子进程中,对安全范围内逐步增大的对抗性近似失败输入进行测量。面对外部可达的复杂模式,我还会考虑解析器或具有合适最坏情况保证的引擎。

延伸阅读 正则表达式
讲清楚了吗?

模式构造

1个问题
91 应怎样把动态文本放入 JavaScript 正则表达式? 中级 偶尔 查看答案 ▾ 收起 ▴

我会先判断动态值属于可信正则源码还是字面数据;多数用户名、扩展名和搜索词都属于数据。固定模式应保留为正则字面量。在 Node 24 上,字面片段经过 RegExp.escape() 后才能嵌入 new RegExp(),可信源码则放在明显分离的路径中。我还会考虑两次解析:构造器形式先执行 JavaScript 字符串转义,再解析正则。测试要包含点号、方括号、圆括号、连字符、反斜杠、换行与 Unicode。转义能阻止语法注入,但性能安全仍需要输入边界和对外围固定模式的审查。

延伸阅读 正则表达式
讲清楚了吗?

运行时语义

1个问题
92 审查代码时,应检查哪些 JavaScript 正则状态与 Unicode 细节? 中级 常见 查看答案 ▾ 收起 ▴

我会先检查标志。使用 gy 时,test()exec() 会修改 lastIndex,因此共享校验器或先测试再执行的序列可能跳过匹配;完整迭代通常用 matchAll() 更清楚。我会确认是否需要 u,并写明目标单位:UTF-16 代码单元、码点、字素、字节、ASCII 数字或 Unicode 十进制数字。在 ECMAScript 中,\d 即使启用 u 仍只匹配 ASCII,而 \p{Decimal_Number} 等属性转义可以表达更广的集合。匹配索引是代码单元偏移,正则匹配既不分割字素,也不规范化文本,因此这些策略需要单独的 API 与测试。

延伸阅读 正则表达式
讲清楚了吗?