偶发 bug 是嵌入式开发里最折磨人的一类问题,它的典型画像是:功能平时一切正常,但运行几小时、几天后突然抽风一次,你还没来得及抓现场,它又自己恢复了。串口偶尔卡死、蓝牙连接说断就断、烧录时灵时不灵,这三类高发故障都有一个共同点——问题不持续出现,导致我们习惯性地怀疑硬件、怀疑环境、怀疑玄学,唯独忘了先怀疑自己的排查方法。
我做嵌入式开发这些年,踩过太多这种坑。这次把串口假故障的换机排除、蓝牙断开的录屏取证、烧录环节的新旧批次对照这三套方法论完整拆开来讲,每一套都是我自己实测过、确实能定位问题的路子。这些东西不挑平台,STM32、ESP32、GD32、杰理或者国产ARM内核的单片机都适用,只要你手里有串口、有蓝牙、有烧录器,这套思路就能直接抄作业。
1. 偶发 bug 的底层逻辑:为什么“重启就好了”会误导你
1.1 偶发 bug 的三个共性特征
先把话说透。偶发 bug 之所以难查,不是因为它没有规律,而是因为它的规律藏在时间、温度和时序里,肉眼很难直接抓到。我总结下来,偶发故障几乎都有三个共同特征。
第一个特征是触发条件苛刻。比如串口 DMA 接收,平时小数据量传输完全正常,但系统跑到某个特定负载组合下,DMA 缓冲区刚好满,又刚好碰上中断优先级被别的任务抢占,一帧数据就丢了。这种故障不是必现的,它需要多个条件在同一时刻重叠,概率自然低。
第二个特征是表现具有欺骗性。串口卡死不一定是串口外设坏了,可能是时钟配置被某个异常分支改了;蓝牙断开不一定是模块坏了,可能是主机端蓝牙协议栈和从机端的连接参数协商出了冲突。你看到的表象和真正的root cause之间,往往隔着两三层间接关系。
第三个特征是排错动作本身会破坏现场。这是最坑的一点。你发现串口假死,下意识按一下复位键,系统恢复了,但你同时把现场的寄存器状态、错误标志位、缓冲区内容全部清掉了。等你想起来要查证据,现场已经被你自己毁掉了。
理解了这三个特征,你就能明白为什么“换一块板子试试”这种看似粗暴的招数,反而是排查偶发 bug 最有效的第一步——因为它制造了一个对照实验,而不是急着去修。
1.2 排查偶发 bug 的核心方法论:三板斧
我这些年总结的偶发 bug 排查套路,其实就三板斧。
第一板斧是换机排除,目的是快速区分故障是“个体硬件问题”还是“共性问题”。如果换一块板子后问题消失,说明至少你的怀疑范围从“全量代码+全量硬件”缩小到了“这块特定板子”上。
第二板斧是取证固化,目的是让“偶发”变成“必现”。既然故障不会乖乖在你想查的时候出现,那就用录屏、日志、抓包工具把现场完整保留下来,把一次性的偶发变成可以反复回放分析的数据。
第三板斧是对照排查,目的是在“新旧差异”里找到变量。很多偶发 bug 其实不是“代码写错了”,而是“新旧不一致”——新批次的芯片、新版本的烧录工具、新换的flash型号,任何一个变量都可能是隐患。
这三板斧不是孤立的,实际排查中经常组合使用。比如先用换机排除锁定个体问题,再用录屏取证抓到蓝牙断开瞬间的时序,最后用新旧批次对照找到烧录差异。下面我分三章把每一板斧的操作细节、我的实际踩坑经历和避坑要点完整讲清楚。
2. 串口假故障的换机排除:别急着调代码,先做对照实验
2.1 什么是“串口假故障”?它和真故障有什么区别
先定义一下什么叫“串口假故障”。我这里说的是:串口外设本身没有损坏,硬件链路也正常,但表现为收发卡死、数据错乱、偶尔丢字节,看起来像硬件坏了,实际上根因却在别处的故障。
真故障和假故障的区分,最有价值的参考指标是故障频率和物理现象。真硬件故障通常随着时间推移越来越频繁,而且往往伴随着电压异常、发热异常或者特定操作下的必现。假故障则通常无规律、可自恢复、换环境后表现不一致。
我遇到过最典型的一个假故障案例:一块 STM32F103 的板子,通过 CH340 转串口接到电脑,运行几个小时后串口必然卡死,重启电脑就好。最初我怀疑 CH340 芯片坏了,换了一块新的,没用;怀疑线缆接触不良,换线,还是没用;最后用示波器抓 TX 引脚波形才发现,单片机其实一直在正常发数据,是 CH340 的驱动在 Windows 下进入了低功耗状态,唤醒逻辑有 bug。这不是硬件问题,是驱动和系统的兼容性“假故障”。
这个案例很好地说明了为什么要先做换机排除——如果你一上来就埋头翻代码、查寄存器,根本不会往驱动方向想,时间全浪费了。
2.2 换机排除的具体操作步骤与判断标准
换机排除的可操作性很强,关键是“换什么、怎么换、对照什么指标”。我整理了一套自己的标准流程,实测下来效率很高。
第一步,先换最容易替换的物理组件。把 USB 线、串口线、转接板、杜邦线逐个替换,每次只换一个变量,换完立即做压力测试。这一步的目的是排除物理链路问题,成本最低,几块钱的线材往往能省下几小时的调试时间。
第二步,再换整块目标板。如果物理链路替换后问题依旧,找一块同批次、同配置的备用板,烧录同一份固件,放在同样的环境里跑同样的测试。这里有一个判断标准:如果新板子也出现同样问题,说明故障是共性的,根源大概率在代码、配置或者环境;如果新板子完全正常,那目标板本身有特殊性,问题就缩小到了板级差异上。
第三步,做交叉验证,这一步容易被忽略但是非常关键。把疑似有问题的板子拿到另一台电脑上、另一个串口调试助手里测试,再把它和正常板子互换位置测试。交叉验证的目的是排除“环境特异性”。我曾经遇到过一块板子在自己工位上怎么都复现不了故障,拿到产线测试工位上必现,最后发现是产线工位的 USB HUB 供电不足导致的。
| 排查层次 | 操作动作 | 判断标准 | 典型耗时 |
|---|---|---|---|
| 物理链路 | 换线、换转接头、换USB口 | 故障是否跟随线材移动 | 10分钟 |
| 目标板 | 换同批次板子 | 故障是否跟随板卡移动 | 30分钟 |
| 环境 | 换电脑、换调试工具、换供电 | 故障是否跟随环境变化 | 20分钟 |
2.3 换机排除中的关键细节:为什么“换完就好了”不一定靠谱
这里我要特别强调一个容易翻车的点:换机排除最怕“换完就好了”的错觉。
你换了一块板子,测试一小时没问题,就宣布故障排除了?别急着下结论。偶发故障的复现周期可能远超你的测试窗口。正确做法是,换机后至少要跑满原故障复现周期的 2~3 倍时间,并且要加负载、加压力。比如原故障是运行 4 小时后出现,新板子至少要连续跑 8~12 小时,并且在测试期间持续增加串口通信量、叠加其他外设中断,才能相对有把握地说“故障确实没有复现”。
另外一个关键是保留故障板。很多人排查时发现换块板子就好了,顺手把故障板扔到角落不管了。这是巨大的浪费——这块板上可能保存着唯一能定位问题的线索。正确做法是把故障板单独标记封存,上的关键波形、寄存器现场如果还能抓,尽量抓下来,再和正常板做对比。
还有一点关于串口电平。如果你在做串口排查,务必确认你的电平转换电路是否可靠。经典的 3.3V 转 1.8V 串口电路,有人直接用三极管搭,这种电路在低速低负载下没问题,但在高波特率或长线传输时,电平上升沿变缓会导致误码和偶发丢字节,表现起来和“假故障”一模一样。排查这类问题,示波器看上升沿时间是最高效的手段。
2.4 实战复盘:一次“坏板子”最终被判无罪的排查记录
分享一个我印象极深的实战案例,完整走一遍换机排除的流程。
某批次产品用了 GD32F470VET6 做主控,客户反馈偶发出现串口无响应,概率大约 1% 的机器会出现,而且出现后断电重启就能恢复。售后寄回三台故障机,我在实验室复现了两天,一台都没复现成功。
我当时的思路是:既然售后能看到现象,我的实验室复现不了,说明复现条件藏在客户的现场环境里。于是我先做换机排除,把故障机留在实验室继续跑,同时拿三台库存正常机做同样的长测。三天后,实验室里的故障机依然没复现,但库存机里有一台开始出现同样的问题。
这时候结论已经变了:这个故障不是“个别机器问题”,而是“某个特定条件下会触发的共性问题”。于是我回头查代码,最终定位到串口 DMA 在半满中断和传输完成中断的竞争条件下,会偶发地丢失一次完成标志,导致后续数据不再触发接收中断。这个 bug 从代码逻辑上看不算难,但触发窗口只有几十个时钟周期,不靠换机排除缩小范围,根本查不到这个方向。
这次经历给我最大的启发是:换机排除的目的不是“证明板子坏了”,而是“证明问题不在某块板子上”,通过排除法把搜索空间一点点压小。
3. 蓝牙断开问题的录屏取证:让偶发故障变成可回放的固定证据
3.1 为什么蓝牙偶发断开特别适合录屏取证
蓝牙故障是偶发 bug 的“重灾区”,因为它牵涉的环节太多了:主机端的协议栈、从机端的模块固件、射频环境里的 2.4G 干扰、两台设备之间的连接参数协商、甚至周围其他蓝牙设备的共存干扰。任何一个环节抖动一下,表现都是“连接断开了”,而且很多时候断开后几秒内会自动重连,你根本来不及反应。
我最早被蓝牙偶发断开折磨是在一个杰理蓝牙方案的音频项目上。客户反馈耳机偶尔断连,时长 1~2 秒,频率大约一小时一两次。这种故障靠人耳去听、靠手去操作,根本抓不住规律。后来我换了思路:把故障变成录像。
录屏取证的核心理念特别简单:既然偶发故障抓不住,那就把“看故障”的过程完整录下来,用视频把一次故障的完整现场固化住,之后可以逐帧回放。而且录屏不止录画面,还要同步录声音、录电脑端的日志输出、录调试工具的实时状态。多路信息叠加在同一时间轴上,故障前后的因果关系就能清晰显现。
这里说的录屏不是拿手机对着屏幕拍,我建议用专业的录屏软件,同时录制屏幕+摄像头+系统音频+麦克风。实际操作中,我会把串口调试助手、蓝牙调试工具、音频波形显示全部铺在桌面上,然后开始录屏,同时用另一个设备模拟用户场景播放音频。故障发生时,屏幕上调试工具的状态变化、日志时间戳、音频中断的瞬间全部被记录下来,比事后回忆可靠一百倍。
3.2 录屏取证的具体操作流程:从目标确立到证据闭环
要做出有用的取证录屏,不是打开录制软件随便录就行。我按下面这套流程操作,成功率最高。
第一步,规划录制内容。明确你要记录哪些信息源:蓝牙模块的串口日志、主控的调试输出、音频播放状态、协议抓包工具的实时窗口。把这些窗口全部排列在同一个屏幕上,保证一次录制能同时捕获所有信息。
第二步,建立统一时间基准。录屏开启前,先在串口调试助手里发一条带有当前时间戳的标记命令,并同时在视频画面里用手势或标志物确认这一瞬间。这样后续分析时,你能把视频画面和日志时间轴精确对齐。
第三步,设置足够的录制时长和画质。偶发故障可能 2 小时才出现一次,录制设置一定要保证长时间稳定录制。分辨率不用太高,1080P 足够看清楚文字,关键是帧率不要低于 30fps,否则蓝牙断开瞬间的闪烁可能被跳帧吃掉。
第四步,故障复现后立即标注。录屏过程中一旦看到故障现象出现,立即通过麦克风语音标注“故障已出现,时间点 XX:XX”,同时用鼠标在屏幕上圈出异常区域。这些标注在回放时是最好的导航标记。
第五步,事后逐帧分析。故障录制完成后,用视频编辑软件逐帧回放故障前后 5 秒的画面,把蓝牙状态指示灯的变化、日志打印的时间差、音频波形的断裂点做成事件时间线,问题往往在这个时间线上一目了然。
| 录制要素 | 推荐工具 / 方法 | 关键要点 |
|---|---|---|
| 屏幕画面 | OBS Studio、Bandicam | 帧率≥30fps,窗口布局固定 |
| 系统音频 | 录制软件内置音频捕获 | 同步记录音频中断瞬间 |
| 串口日志 | 串口调试助手 + 时间戳 | 日志窗口保持在屏幕显眼位置 |
| 协议抓包 | Wireshark、蓝牙抓包器 | 同步抓取空中数据包 |
| 时间基准 | 启动时的标记命令 | 视频画面与日志时间轴对齐 |
3.3 蓝牙取证中容易被忽略的分析视角
录屏拿到手以后,怎么从视频里挖掘有效信息?我总结了三个容易忽略的视角。
第一个视角是断开前的最后交互。蓝牙断开前,主机端和从机端往往会有一次“最后的对话”。比如 A2DP 切 SCO 模式时,音频链路要从高质量音乐模式切换到通话模式,这个切换过程如果没有按协议规范处理,就会造成断流甚至断连。回放录屏时,特别留意断开前 1 秒内串口日志里有没有出现模式切换、连接参数更新的记录。
第二个视角是射频环境的干扰证据。如果在故障时刻附近,串口日志里出现了大量的 ACK 超时或重传记录,说明空中链路质量有问题。这时候录屏画面上只有一个间接证据,但它指引你去做进一步的频谱分析——比如用频谱仪或者带频谱功能的工具看 2.4G 频段的占用情况。我之前遇到过一起蓝牙键盘频繁断连的问题,最后就是通过录屏发现断连时间段和某个工位的微波炉使用时间高度重合,挪开微波炉后问题消失。
第三个视角是**“重连成功”的延迟规律**。很多偶发断连实际是“闪断”,即断开后设备自动重连。回放时记录每一次断开的持续时间,如果断开时长呈现某种规律性,比如总是 1.5 秒左右,说明重连机制在起作用但效率偏低;如果断开时长随机性很大,则可能牵涉到更复杂的协议栈异常。
关于蓝牙调试,我再多说一句工具层面的事。如果项目里用的是 HC05 这类经典蓝牙模块,它的 AT 指令日志能提供大量信息,但前提是你在固件里把调试串口配置好了。杰理方案则是在 SDK 里打开对应的 log 输出宏。调试信息尽量往“多打印”方向做,虽然会影响一点运行效率,但偶发 bug 排查阶段信息量比效率更重要。
3.4 实操分享:从录屏到定位的完整链路
我最近一次用录屏定位蓝牙问题,是一个基于 ESP32S3 的蓝牙数传项目。现场反馈是数据传输偶尔中断,持续时间约 2~3 秒后自行恢复,一天出现 3~5 次。
我按上面流程搭了录制环境:电脑屏幕左边是串口调试助手,显示 ESP32S3 的调试日志;中间是蓝牙调试工具的实时数据速率曲线;右边是 Wireshark 的抓包窗口。录制 6 小时后,故障复现了两次。
回放视频时,我注意到一个之前用逻辑分析仪都没抓到的细节:每次数据中断前,串口日志里都会先出现一条“connection parameter update request”的打印,紧接着数据速率曲线掉到零,约 2 秒后恢复。这说明问题不在物理层,而在连接参数协商环节——从机请求更新连接间隔,主机响应后,双方进入了短暂的重新同步状态,而这个状态下的数据缓冲没有做好。
定位后修复就很快了:在从机固件里优化了连接参数更新的触发条件,并把缓冲区策略改成更新期间不丢弃数据。修正后连续测试 48 小时,故障未再复现。整个排查过程,录屏取证是最关键的一步——如果不是视频把“参数更新请求”和“断流”这两件事的时间顺序清晰记录下来,靠直觉猜不知道要猜多久。
4. “新旧批次对照”的烧录排查:变量隔离是偶发问题的最快解法
4.1 为什么烧录环节会出现“时灵时不灵”
烧录失败或者烧录后运行异常,很多人第一反应是“烧录器坏了”或者“芯片坏了”。但在我的经验里,烧录类的偶发问题背后,最常见的原因是新旧批次之间的隐性差异。
什么是新旧批次差异?同一个型号的芯片,晶圆厂不同批次流片可能在电气特性上有细微差别;同一个 flash 芯片,原厂和兼容厂在时序参数上可能不一样;同一款开发板,不同批次可能换了不同供应商的物料。这些差异在常规运行中完全不体现,但烧录是一个对时序极其敏感的过程,一点细微的时序偏差就可能导致烧录失败或者烧录后固件不稳定。
我踩过最典型的一个坑是:一批板子用的 flash 芯片从原厂换了兼容型号,外观一模一样,丝印略有不同。前两版固件烧录一切正常,第三版固件编译出来体积比之前大了 40KB,烧录时问题就来了——大约 30% 的板子烧录到一半报错,报错的板子重新上电后又还能正常跑旧程序。表面看是“烧录失败”,实际上是新固件体积增大后,覆盖到了兼容 flash 时序参数不达标的地址区域。
这个案例完美说明了为什么“新旧批次对照”是烧录排查的法宝——你需要把“时间”和“批次”两个变量纳入排查范围,而不是只在“烧录器坏没坏”上打转。
4.2 新旧批次对照排查的五个验证维度
当烧录出现偶发失败或者烧录后偶发异常时,我建议从五个维度做新旧批次的对照排查。
第一个维度,固件本身的新旧对照。编译产物是否有差异——代码改动过什么、编译器版本、优化级别、链接脚本有没有变化。web 开发里有个说法是“判断前后端 bug 先看发布记录”,嵌入式也一样,先查 Git 提交记录,确认“上一次正常”和“这一次异常”之间代码到底改了什么。
第二个维度,烧录工具链的新旧对照。你用的烧录软件版本、烧录器固件版本、烧录算法文件(比如 Keil 的 FLM 文件、ESP32 的 Flash Download Tools 配置)有没有变化。很多“以前能烧现在不能烧”的问题,根源就在工具链版本升级后默认参数变了。
第三个维度,芯片和存储物料的新旧对照。这是最容易被忽视的。芯片丝印、批次号、封装形式、flash 型号、晶振型号,全部记录下来和正常板做对比。如果可能,把正常板和异常板的物料批次排列成表格,一眼就能看出变量。
第四个维度,烧录环境的新旧对照。供电电压、烧录线长、USB 口能力、环境温度,这些“软条件”也会影响烧录稳定性。特别是供电,烧录瞬间芯片的电流浪涌比正常运行大很多,USB 口供电不足是很常见的隐性问题。
第五个维度,操作流程的新旧对照。是不是有人改了烧录流程的某个顺序?比如原来先断电再插烧录器,现在变成了带电插拔;原来烧录前有自动擦除,现在某个版本的软件默认不擦除。操作流程的变化是最隐蔽的变量,因为它藏在“人”的因素里,代码和硬件都没变。
| 对照维度 | 检查内容 | 排查方法 |
|---|---|---|
| 固件产物 | 代码改动、编译器版本、链接脚本 | 查看 Git 提交记录,对比 bin/hex 文件 hash |
| 烧录工具链 | 烧录软件版本、烧录器固件、FLM 算法 | 记录版本号,必要时降级到旧版本验证 |
| 物料批次 | 芯片丝印、flash 型号、晶振规格 | 拆机对比,建立物料批次台账 |
| 烧录环境 | 供电电压、线长、USB 口、温度 | 用稳压源独立供电,排除环境干扰 |
| 操作流程 | 烧录顺序、擦除选项、复位方式 | 回放操作录像,对照标准作业流程 |
4.3 烧录偶发失败的高效排查路径:先软件后硬件、先对比后更换
烧录出问题时,我的排查顺序向来是“先软件后硬件、先对比后更换”,这条路最省时间。
先做软件对照。把编译产物用比对工具逐字节对比,如果两个 bin 文件在某个地址区域的差异刚好对应到问题现象的描述,那大概率就是固件改动引入的问题。这里我推荐用 Beyond Compare 这类十六进制对比工具,重点看差异区域的规模和位置。
如果固件对比没问题,再回到烧录配置文件对照。Keil 的 Flash Download 配置、ESP32 的烧录地址和波特率、STM32CubeProgrammer 的连接模式,每一项都截图保存。很多烧录问题其实是配置文件的某个参数在不同版本软件里被默认改了,但没人注意。
然后做硬件侧对照。这个阶段重点测供电和时序。用示波器抓烧录瞬间的 VCC 跌落幅度,如果跌落超过 5%,就换独立电源重新烧录测试。顺便量一下复位引脚的时序,确保烧录器复位芯片的时序和芯片要求匹配。
最后才考虑更换硬件测试。换同批次芯片测试、换旧批次芯片测试、换烧录器型号测试。这一步的目的是确认问题是不是“某个批次的物料”特有的。如果旧批次芯片烧录全部正常,新批次芯片烧录偶发失败,那就是物料批次差异的实锤,接下来找芯片供应商要批次报告就行了。
4.4 烧录排查的实战记录:一次“新旧批次对照”定位的完整过程
分享一次完整的烧录批次排查,这个案例几乎涵盖了前面讲的所有维度。
项目用 AT89S52 做控制板,一直用的是原厂芯片,烧录工具是第三方通用编程器。某批次生产时,采购因为缺货换了同型号但不同批次的芯片。产线反馈这批芯片烧录时偶尔报“写校验失败”,概率约 5%,重烧一次又大多能成功。
我拿到样品后先做固件对比——hex 文件没动过,排除代码因素。再看烧录工具链——软件和硬件都没变,排除工具因素。然后拆开芯片对比丝印,发现新批次和旧批次的丝印虽然型号一样,但顶部标记多了一行我们不认识的代码。查芯片数据手册的勘误表,发现这个新批次芯片在某个地址范围的编程时序要求更严格,编程脉冲宽度需要比旧批次延长。
解决方式是更新烧录器软件里的芯片型号配置,从“自动检测”改为“手动指定新批次型号”,同时把编程脉冲宽度参数调整到符合新批次要求的值。调整后测试 200 片,零失败。
这个案例的核心教训就是:烧录器配置文件里的芯片型号参数,不是随便选的,它对应着具体的时序参数组。很多时候更稳妥的做法是在更换芯片批次后主动查询芯片手册或者联系原厂确认参数差异,而不是等到产线爆出问题再排查。
5. 偶发 bug 排查的通用工具箱与经验总结
5.1 建立自己的“故障排查优先清单”
经历过这些案例后,我建立了一份属于自己的故障排查优先清单,遇到偶发 bug 时就按顺序过一遍。这份清单没有玄学,全是物理手段。
第一优先,确认问题的可复现性。先花时间想办法提高复现概率,哪怕只从偶发提高到“一小时一次”,排查效率就能提升一个量级。具体手段包括加长测试时间、加大通信负载、改变工作模式、调整环境温度。
第二优先,做换机排除实验。物理链路、目标板、环境逐个替换,用对照实验逼出变量。这一步通常能帮你把问题范围缩小一半以上。
第三优先,上取证工具。录屏、日志、抓包、示波器波形,所有能记录现场信息的工具全部打开,让故障“留下痕迹再走”。
第四优先,做新旧对照。代码版本、工具链版本、物料批次、操作流程,任何有“新旧差异”的地方都值得查一遍。
5.2 工具链配置与调试信息输出的优先级
排查偶发 bug 阶段,调试信息的“覆盖率”比“性能”重要。我建议在正式排查前,确保你的工程里打开了足够的调试输出通道:
- 串口调试信息尽量包含时间戳、函数名、关键变量值,偶发问题定位时没有这些信息等于盲查。
- 蓝牙项目强制开启协议栈日志,尤其是连接状态变化、断连原因码、重连时间这仨关键信息。
- 烧录环节保留每次烧录的完整日志,包括烧录软件版本、目标芯片型号、烧录起始地址、校验结果,形成可追溯的记录。
这些工作看着麻烦,但都是“一次配置、长期受益”的事。我自己踩过无数次“当初没打日志,现在排查无从下手”的坑,现在总是在项目启动阶段就把调试基建搭好。
5.3 关于排查心态的几句实话
做技术的人容易有一个通病:遇到偶发 bug 就想“根治”,恨不得一次就把根因挖出来。但我的经验是,面对偶发问题,正确的心态应该是“先压缩未知空间,再攻克剩余目标”。换机排除、录屏取证、新旧对照,本质上都是压缩未知空间的手段。
还有一个心态上的经验:不要一个人死磕。偶发 bug 经常是“一个人怎么都想不通,两个人讨论一下突然就有思路了”。因为每个人对系统的假设不同,你的盲区可能恰好是别人的知识背景。把录屏拿给同事看、把两张批次照片放在一起对比,往往会有意想不到的发现。
我自己现在的习惯是每次处理完一个偶发 bug,就把完整排查记录整理成一份简短的笔记,包括现象、排查路径、根因、修复方法四部分。一年下来翻看这些笔记,你会发现自己对系统的理解发生了质变。当下次再遇到一个看似全新的偶发 bug,你可能一眼就能在旧笔记里找到似曾相识的线索。