凌晨两点,测试同学发来一条崩溃前的现场:某个页面反复进出十几次后,内存占用从 80MB 一路爬到 600MB 才被系统杀掉。这种「缓慢增长型」泄漏,靠肉眼看代码基本抓不住,必须上 Instruments。问题是团队本地 Mac 常年被模拟器和构建任务占满,再开一份 Instruments 采样,风扇转到起飞,数据还不干净。后来把这套排查流程搬到了云端 Mac mini 上,独享物理机没有邻居抢资源,采样噪音明显更小,这篇记一下具体怎么做。
为什么要挪到独享物理机上排查
Instruments 本身对 CPU 和内存都有不小的开销,Leaks 模板会周期性做堆扫描,Allocations 记录每一次分配调用栈。如果宿主是被多个任务分时的共享环境,采样时间线里会混入大量无关的调度抖动,曲线不干净,容易误判「增长点」。独享物理机的好处很朴素:你看到的每一次内存跳变,基本都能对应到自己代码里的一次操作,不用先排除「是不是别人的任务在抢资源」。
排查内存问题最怕的不是找不到线索,而是找到一堆假线索——环境噪音越大,假线索越多。
准备工作:屏幕共享 + 版本对齐
云端 Mac mini 开机后,先用系统自带屏幕共享(VNC)连上去,分辨率至少设到 1920x1080,Instruments 的时间线在低分辨率下会挤成一团,细节根本看不清。
# 本地终端,确认可以先用 SSH 探活
ssh dev@<你的实例地址> "sw_vers -productVersion; xcodebuild -version"
# 用 VNC 客户端连接,地址为实例分配的内网/公网地址
open "vnc://dev@<你的实例地址>"
连上去之后第一件事是核对 Xcode 版本与你本地开发机一致,尤其是 Instruments 模板库的版本差异会导致某些新特性(比如 Swift Concurrency 相关的追踪)缺失。用 xcode-select -p 确认命令行工具路径正确,再打开 Xcode → Open Developer Tool → Instruments。
用 Leaks 模板先定位泄漏点
新建 Profile,选择设备(可以是连到云端 Mac mini 上的真机,也可以用模拟器先复现),模板选 Leaks。Leaks 会在后台周期性扫描堆内存,标红的对象就是引用计数归零后仍然存在的孤儿对象。
操作步骤:
- 启动录制,在 App 里重复触发嫌疑操作(比如反复进出某个页面)15~20 次;
- 观察左侧 Leaks 轨道,红色标记出现的时间点对应哪一次操作;
- 点开对应的 Leak 记录,右侧 Extended Detail 里能看到分配调用栈,直接跳到具体的类和方法。
Leaks 的局限是它只报告「确定泄漏」,像 NSTimer 强引用、闭包捕获 self 这类「引用链没断但逻辑上应该释放」的情况,Leaks 往往抓不到,这时候要换 Allocations。
用 Allocations 看增长曲线
新建 Profile,模板选 Allocations,勾选 Record Reference Counts。重复同样的操作序列,每做完一轮就手动点一次 Mark Generation,这样时间线上会打一个标记点,方便对比「每一轮之后,内存有没有回落到起点」。
关键读法:如果内存曲线在多轮操作后呈阶梯上升、且每一级台阶高度接近,基本可以确定是某个固定对象或数组每次操作都在累加。切到 "All Heap Allocations" 视图,按 Growth 排序,配合 Generation 对比,能直接看到哪个类的实例数量在稳定增加。
| 观察项 | Leaks | Allocations |
|---|---|---|
| 能否发现闭包/Timer 循环引用 | 弱 | 强 |
| 定位效率 | 快,直接标红 | 需要多轮对比 |
| 适用阶段 | 初筛 | 精确定位增长源 |
结合 Memory Graph 交叉验证
Instruments 找到嫌疑类之后,回到 Xcode 里跑一遍 Debug Memory Graph(Xcode 调试栏的内存图标),在同样的操作序列后触发。Memory Graph 会画出对象的引用关系图,紫色感叹号标记的就是可能的循环引用。这一步是对 Instruments 结论的二次确认,尤其能清楚看到「谁在强引用谁」,比 Instruments 的调用栈更直观地定位到具体一行 self.completion = { self.doSomething() } 这类闭包捕获问题。
修好之后,不要立刻下结论,回到 Allocations 里再跑一遍同样的操作序列,确认 Mark Generation 之间的曲线是水平的而不是阶梯上升,这才算真正验证了修复有效。
常见坑与检查清单
- 录制前一定先做一次「预热」操作(启动、登录等一次性分配),避免把冷启动的正常分配误判为泄漏;
- Release 模式和 Debug 模式的内存行为不完全一致,最终结论要在 Release 配置下复核一次;
- 云端 Mac mini 断开屏幕共享重连后,Instruments 会话可能中断,建议长时间录制前先用
caffeinate -i防止系统休眠打断采样; - 每次修复后都用 Allocations 的 Generation 对比法回归验证,而不是仅凭代码审查就下结论。
常见问题
本地 Mac 性能不够,能用云端 Mac mini 跑 Instruments 吗?
可以。Instruments 对 CPU 与内存都有开销,独享物理机不与他人抢资源,分析时的采样噪音比共享环境更小,数据更可信。
屏幕共享分辨率低会影响 Instruments 操作吗?
会影响时间线细节的可读性,建议把 VNC 分辨率设到 1920x1080 以上,并在 Instruments 里放大关注的时间区间再截图记录。
泄漏定位后要不要马上退租机器?
不建议。先在同一台机器上打补丁验证曲线是否收敛,确认修复有效后再决定是否结束本次租期,避免来回搭建环境。
控制台://order
现在就要一台?
独享物理 Mac mini,按天起租,约 4 分钟从付款到可用。