重启不是玄学:电脑为什么一关一开,就像治好了 99% 的毛病?
先说结论
重启不是魔法,也不是把所有故障都修好了。它更像是把一间住了很久、已经乱到找不到东西的房间清空:借出去但没归还的物品被收走,排队的人重新取号,临时便签被撕掉,门锁和电器重新检查。系统因此回到了一个更干净、更容易预测的起点。
所以,“重启解决了问题”通常意味着:故障藏在易失状态里,而不是硬件已经坏掉、配置一直错误或程序本身存在根因。
你一定见过这样的场景:浏览器突然打不开新标签页,文件明明存在却提示“正在使用”,远程桌面连不上,风扇像小飞机一样转,内存还剩很多却不停卡顿。你先关一个窗口,再关几个程序,最后抱着“试试看”的心态重启。
电脑重新亮起来后,刚才那个很难解释的毛病消失了。
这就是大家常说的“重启能解决 99% 的问题”。它当然不是一个经过严格统计的 99%,而是一种非常生动的工程经验:很多问题不是永久损坏,而是系统在长时间运行中积累了太多没有及时清理的临时状态。

图 1:重启像把“住乱了”的系统清场复位。原创配图。
把电脑想成一间一直有人使用的房间
刚搬进去时,房间很整齐。桌上只有一台电脑,柜子里有几份文件,门口有两双鞋。
但如果这间房连续住三个月,却从来不做大扫除,会发生什么?
- 快递盒越来越多,虽然每个盒子都不大,但过道被堵住了。
- 借出去的剪刀、充电器和钥匙没有归还,东西并没有“消失”,只是没人知道它在哪里。
- 门口排着很多人,已经离开的客人还占着号码。
- 桌上贴满旧便签,大家仍然按照过期的便签做决定。
- 两个人各自拿着一把钥匙,互相等对方先开门,谁都不愿意松手。
系统里的“房间”就是内存、文件句柄、网络连接、线程、锁、缓存、驱动状态和各种服务上下文。它们有一个共同特点:启动时会被建立,运行中会被修改,退出或重启时才有机会统一回收。
下面这张图把最常见的四种“乱”放在了一起。

图 2:状态泄漏、内存碎片、连接堆积,以及锁和旧缓存,是重启经常能缓解的四类问题。
状态泄漏:借出去的东西没有放回原位
“泄漏”不一定是水从水管里流出来。对程序来说,泄漏更像是“借了资源,但忘了归还”。
程序打开一个文件,系统会给它一个文件描述符;程序创建一个网络连接,系统会保存连接状态;程序申请一块内存,分配器会记住这块空间归谁使用。如果程序退出时没有正确关闭,或者它一直运行、从来不退出,那么这些资源就可能持续占着位置。
一次泄漏可能小得几乎看不见。比如每处理一千个请求只多留一个句柄,一天之后可能没有任何感觉;几周之后,系统却开始提示“打开文件太多”“无法创建线程”或“连接失败”。
这就是为什么重启一个服务有时比“再点一次按钮”有效:服务进程结束后,操作系统会回收该进程名下的内存、句柄、线程和连接。房间里那些没有登记归还的物品,会随着住客离开而被物业统一收走。
macOS 的 vm_stat 会把虚拟内存拆成很多页来观察;Linux 则常见 /proc/meminfo、free 和进程的 RSS。它们不是“电脑健康分数”,而是帮助我们确认房间里到底堆了什么。

图 3:真实的 macOS vm_stat 输出。数字会随机器和时间变化,重点是观察趋势,不是迷信某个固定值。
内存碎片:柜子还有缝,却塞不进大箱子
很多人看到“可用内存还有几 GB”,就会问:既然还有空间,为什么程序还是申请失败?
因为“总空位”不等于“连续的大空位”。
把内存想成一个有很多格子的柜子。程序先放入一个小盒子,又拿走另一个盒子,再放入一个大箱子。经过很多次申请和释放以后,柜子可能到处都有小缝,但没有一块连续的空位能放下大箱子。
这就是内存碎片最容易理解的版本。真实系统比这个复杂:用户态分配器、内核页分配器、不同大小的对象、内存映射和缓存都会影响布局。现代操作系统会尽力复用和整理空间,但整理本身也需要时间,并且并非所有内存都能随便移动。

图 4:蓝色格子表示已占用区域,浅色格子是分散的空位;“还有空位”并不代表能满足连续大块分配。
Linux 内核文档把 compaction(内存压缩整理)描述为把可移动页搬到一起,从而形成更大的连续空闲区域。这个过程像把衣柜里的小衣物先集中到一侧,让另一侧腾出完整空间,但它不是免费的:搬东西需要 CPU,也受不可移动页、正在使用的页和分配时机影响。
因此,重启有时会让内存表现“突然变好”,并不是重启凭空创造了内存,而是旧进程、旧映射和旧缓存全部结束后,新的进程在更干净的布局上重新分配。

图 5:真实的 Ubuntu free -h 与 ss -s 汇总。文章只保留统计项,不展示地址或机器名。
连接堆积:窗口有限,旧号码却没清掉
网络连接可以想成银行窗口。
服务器只有有限数量的连接槽位、文件描述符、线程和端口。一个请求来了,系统为它分配资源;请求结束后,资源应当尽快归还。但实际网络里还有重传、超时、半关闭、连接复用和 TIME-WAIT 等状态。某些状态本来就是协议设计的一部分,不是错误;问题在于它们的数量、持续时间和业务流量不匹配。
RFC 9293 说明了 TCP 状态机中的 TIME-WAIT:主动关闭连接的一方需要在一段时间内保留状态,以避免旧报文干扰后续连接。生活中,这就像快递柜不会在包裹刚取走的一秒钟就立刻把编号交给另一个人,系统要留一点时间确认“旧包裹真的结束了”。
如果应用不断创建短连接,却没有连接池、超时和正确的关闭逻辑,队列就会越来越长。最终表现可能是“偶尔连不上”“新请求卡住”“端口用完”或“服务重启后马上恢复”。

图 6:真实的 TCP 状态汇总。看趋势比看一次快照更有意义;TIME-WAIT 本身不等于故障。

图 7:最小实验让 socket 数量分批增长;进程退出时,操作系统会一次性关闭这些端点。
锁死与旧缓存:两个人都等对方先让路
还有一类问题不一定表现为“内存不够”,而是某个状态已经走偏了。
例如:
- 线程 A 拿着钥匙 1,等待钥匙 2;线程 B 拿着钥匙 2,等待钥匙 1。
- 服务发现缓存里保存着旧地址,但程序没有重新查询。
- 驱动已经重新加载,用户态程序却仍然相信旧设备状态。
- 一个失败的后台任务留下了“正在执行”的标志,前台因此永远等待。
这像两个人站在一扇窄门两侧:A 不退,B 也不退,最后整个房间都无法通行。
有些系统可以通过超时、重试、清缓存、释放锁或重启单个服务恢复;如果状态分散在多个进程、内核模块或桌面服务之间,重启操作系统就会把这些易失状态一起打断。

图 8:重启的本质是有序结束旧状态,然后用新的进程、服务和连接重新开始。
我们亲手做一个“状态越来越多”的小实验
下面的实验没有调用第三方服务,也没有修改系统设置。程序每一步都保留一批内存块,然后打印进程峰值 RSS;进程结束时,这些内存由操作系统回收。

图 9:真实实验输出。它不是模拟“所有内存泄漏”,但能直观展示“进程不结束,进程内状态就会持续存在”。
这也是“重启有效”的关键边界:重启能清掉进程拥有的临时状态,却不能保证程序下一次启动后不会再次泄漏。如果每次启动后 RSS 都慢慢上涨,那么重启只是把问题曲线从零重新画了一遍。
为什么“关机再开机”有时和“重启”不一样
在 Windows 上,用户看到的“关机”并不总是等同于一次完整的内核重置。快速启动会让部分系统状态写入磁盘,以缩短下一次启动时间;而“重启”通常会走完整的重新启动路径。排障时,如果目标是清理驱动、内核和服务状态,应优先选择明确的 Restart,而不是只点 Shut down 再开机。
这并不意味着快速启动是坏功能。它是“每天快速回家”的设计;重启则更像“把房间彻底清空后重新开门”。不同目标,动作就不同。
一次真正有价值的重启,应该留下证据
如果每次遇到问题都直接重启,我们只能知道“它暂时好了”,不知道“为什么好了”。更好的顺序是:先记录,再复位,再验证。
Windows 11:PowerShell 诊断与安全重启
下面脚本只用系统自带命令。默认先把报告写入桌面,再询问是否重启;只有输入 RESTART 才会继续。它不上传数据,也不修改系统配置。
$ErrorActionPreference = "Continue"
$stamp = Get-Date -Format "yyyyMMdd-HHmmss"
$report = Join-Path $env:USERPROFILE "Desktop\restart-room-$stamp.txt"
"Restart room evidence - $stamp" | Set-Content $report
"`n[OS]" | Add-Content $report
Get-CimInstance Win32_OperatingSystem | Select-Object Caption,Version,LastBootUpTime | Format-List | Add-Content $report
"`n[Top memory processes]" | Add-Content $report
Get-Process | Sort-Object WorkingSet64 -Descending | Select-Object -First 12 Name,Id,@{N='WorkingSetMiB';E={[math]::Round($_.WorkingSet64/1MB,1)}} | Format-Table | Out-String | Add-Content $report
"`n[Network state counts]" | Add-Content $report
netstat -ano | Select-String 'TCP' | ForEach-Object { ($_ -split '\s+')[-1] } | Group-Object | Sort-Object Count -Descending | Format-Table | Out-String | Add-Content $report
Get-Content $report
$answer = Read-Host "Evidence saved. Type RESTART to reboot, anything else to stop"
if ($answer -ceq 'RESTART') { Restart-Computer -Confirm }
人工执行就是把内容保存为 restart-room.ps1,在 PowerShell 中运行 Set-ExecutionPolicy -Scope Process Bypass 后执行脚本。Agent 执行时应把“采集证据”和“重启”拆成两个动作:先读取报告,向人类说明影响范围,得到明确授权后再执行 Restart-Computer,不能为了“修好”而自动跳过确认。
Ubuntu 26.04:Bash 诊断与安全重启
#!/usr/bin/env bash
set -euo pipefail
stamp="$(date +%Y%m%d-%H%M%S)"
report="$HOME/restart-room-$stamp.txt"
{
echo "Restart room evidence - $stamp"
echo
echo "[OS]"
uname -srm
uptime
echo
echo "[Memory]"
free -h
echo
echo "[Socket summary]"
ss -s
echo
echo "[Failed services]"
systemctl --failed --no-legend || true
echo
echo "[Compaction counters]"
grep -E '^(compact_|allocstall_)' /proc/vmstat | head -30 || true
} | tee "$report"
read -r -p "Evidence saved to $report. Type RESTART to reboot: " answer
if [[ "$answer" == "RESTART" ]]; then
sudo systemctl reboot
fi
人工执行前先确认自己在正确的机器上,并把报告复制到工单或本地。Agent 执行时建议要求它返回报告路径、失败服务数量、TCP 汇总和当前 uptime;只有在维护窗口内、且人类明确批准时才调用 sudo systemctl reboot。如果 Agent 只说“重启后应该就好了”,那不是完整的排障记录。
macOS 26:zsh 诊断与安全重启
#!/bin/zsh
set -u
stamp="$(date +%Y%m%d-%H%M%S)"
report="$HOME/Desktop/restart-room-$stamp.txt"
{
echo "Restart room evidence - $stamp"
echo
echo "[System]"
sw_vers
uptime
echo
echo "[Virtual memory]"
vm_stat | head -18
echo
echo "[Memory pressure]"
memory_pressure | head -22
echo
echo "[TCP state counts]"
netstat -an -p tcp 2>/dev/null | awk 'BEGIN{print "addresses omitted"} /^tcp/{state[$NF]++} END{for(s in state) print s, state[s]}' | sort
} | tee "$report"
printf 'Evidence saved to %s. Type RESTART to reboot: ' "$report"
read answer
if [[ "$answer" == "RESTART" ]]; then
sudo shutdown -r now
fi
人工执行时,不要把 sudo 密码交给脚本或 Agent;让系统自己的终端完成授权。Agent 可以帮忙解释 memory_pressure 和 TCP 状态,但不应该把一次快照误判为根因,更不能把完整日志上传到第三方服务。
“重启”不是第一步,也不是最后一步
下面是我更推荐的排障阶梯:

图 10:重启是中间的一种复位手段,根因修复仍然要靠配置、升级、代码和容量治理。
先记录时间、错误信息、内存/CPU/连接曲线;然后尝试重启单个应用。若问题只影响一个服务,就不要先把整台机器踢出房间。应用无效,再重启相关服务;如果多个服务共享同一个内核、驱动或网络栈,再考虑操作系统重启。
重启之后要验证三件事:
- 问题是否真的消失,而不是因为刚好流量变小?
- 资源曲线是否重新上涨?
- 一段时间后是否会以同样的错误回来?
如果答案是“会”,那重启只是复位按钮,不是修复方案。
哪些问题重启通常治不好

图 11:如果房子的地基坏了,打扫房间只能让它暂时看起来整齐。
硬件损坏、磁盘即将报废、温度过高、错误配置、证书过期、磁盘写满、程序逻辑错误、数据库数据损坏,都不会因为重启而真正消失。程序有内存泄漏时,重启只会把泄漏计数器归零;配置写错时,系统启动后还会再次读取同一个错误值。
这也是为什么成熟的值班同学会把“重启后恢复”标记为症状缓解,而不是“根因已修复”。
Q&A:关于重启的几个常见误解
重启是不是会“清空所有内存”?
它会结束大多数用户态进程并重新初始化系统,但不是把内存芯片物理擦除。固件、磁盘数据、配置文件和某些持久化状态仍然存在。重启清的是运行时上下文,不是所有数据。
内存占用高就一定要重启吗?
不一定。文件缓存、压缩内存和正常的工作集都会占用内存。先看可回收空间、swap、内存压力、进程趋势和是否存在 OOM/分配失败。一个“使用率高但压力低”的系统,可能运行得很好。
TIME-WAIT 很多是不是网络坏了?
不一定。TIME-WAIT 是 TCP 可靠关闭的一部分。真正要看的是数量是否异常、是否持续增长、是否伴随端口耗尽、连接失败或延迟上升。不要为了追求“数字变成零”而随意关闭协议保护。
为什么重启应用有时就够了?
因为泄漏或锁可能只存在于这个进程里。重启单个应用影响小、速度快,也更容易验证。如果应用重启后马上再次出问题,就应该继续查日志、版本、配置和资源释放路径。
最好的重启频率是多少?
没有一个适用于所有机器的数字。桌面电脑可以根据更新和异常情况重启;服务器更应该依靠监控、资源上限、连接池、超时、滚动发布和故障演练,而不是把“每周重启”当成唯一的稳定性策略。
最后,把“玄学按钮”变成工程动作
重启之所以看起来像万能药,是因为它一次性做了很多人平时不愿意做、也很难逐项做完的事情:结束进程、关闭连接、释放句柄、丢弃旧缓存、重建服务、重新加载驱动、重新建立网络状态。
它像把房间里所有人请出去,再重新发钥匙、排队号和座位表。房间因此暂时恢复秩序,但如果有人一直把垃圾扔在地上,下一轮仍然会乱。
真正专业的目标不是“让重启继续解决 99% 的问题”,而是让每次重启都留下足够证据,直到我们能回答:谁制造了垃圾,为什么没人清理,为什么系统没有早点报警,以及怎样让它下次不再发生?
参考资料
- Microsoft Learn:Application or Service Memory Leaks Troubleshooting Guidance
- Microsoft Learn:Improve app performance by reducing memory and disk usage
- Microsoft Learn:Evaluate Fast Startup Using Windows Performance Toolkit
- Linux kernel documentation:Compaction
- Linux kernel documentation:TCP/IP sysctl
- RFC 9293:Transmission Control Protocol
- Apple Support:Activity Monitor User Guide