查找循环引用(Strong Reference Cycles)是解决内存泄漏最直接的手段。Xcode 为我们提供了两把“手术刀”:Memory Graph 适合定位具体的引用关系,而 Instruments 适合全局监控内存增长趋势。
1. 使用 Xcode Memory Graph Debugger(首选,最直观)
这个工具能让你在 App 运行时直接看到内存中所有对象的“关系网”。
操作步骤:
-
运行 App:在模拟器或真机上运行你的项目。
-
复现路径:进入怀疑有内存泄漏的界面(例如一个复杂的详情页),然后退出该界面。重复 2-3 次。
-
点击捕获:在 Xcode 底部的控制栏,点击 Debug Memory Graph 按钮(三个小圆圈连线的图标)。
-
寻找异常:
- 观察左侧面板:Xcode 会用紫色感叹号标记出它怀疑存在循环引用的对象。
- 查看引用图:点击一个对象,中间面板会显示谁在持有它。
-
识别环路:
- 寻找那些形成闭环的连线。例如:
ViewControllerClosure ContextViewController。 - 实线代表强引用(Strong),虚线代表弱引用(Weak)或无主引用(Unowned)。
- 寻找那些形成闭环的连线。例如:
2. 使用 Instruments - Leaks(全局监控)
如果你不确定哪个界面在泄漏,Instruments 能够全方位扫描。
操作步骤:
-
启动工具:按下
Command + I调出 Instruments,选择 Leaks 模板。 -
开始记录:点击左上角的红色 Record 按钮,App 会启动。
-
操作 App:像平常一样操作你的 App。如果在底部的 Leaks 轨道 上出现了红色的小叉(Red X) ,说明此时检测到了无法被回收的内存。
-
分析详情:
- 点击下方的 Cycles & Roots 视图。
- Instruments 会自动识别出导致泄漏的“引用环”。
- 你可以点击某个节点,在右侧的 Extended Detail 中看到该引用是在哪一行代码产生的。
3. 两种工具的互补策略
| 场景 | 推荐工具 | 原因 |
|---|---|---|
| 快速定位已知页面的泄漏 | Memory Graph | 响应快,能直观看到 weak 还是 strong 指向。 |
| 无法确定泄漏发生的时间点 | Leaks | 实时监控,适合长时间、大范围的路径测试。 |
| 分析闭包(Closure)捕获 | Memory Graph | 它可以清晰地显示 malloc_block 与对象的持有关系。 |
4. 实战排查小技巧
-
Malloc Stack Logging(必开项) :
在调试前,建议在 Xcode 的
Scheme->Edit Scheme->Diagnostics中勾选 Malloc Stack 里的 Live Objects Only。开启后,在 Memory Graph 中点击任意对象,你就能直接看到它是在哪行代码被创建的。 -
搜索过滤:
在 Memory Graph 左侧下方的搜索框输入你的类名(如
MyViewController),如果页面明明关了,搜索还能搜到实例,说明它一定被某处强引用的“环”给勾住了。
英文版
8-21. [Memory Management] How to use Instruments or Xcode Memory Graph to find Strong Reference Cycles?
Finding strong reference cycles (Retain Cycles) is the most direct way to resolve memory leaks. Xcode provides two "surgical tools": Memory Graph is best for locating specific reference relationships, while Instruments is ideal for monitoring overall memory growth trends.
1. Using Xcode Memory Graph Debugger (Preferred, Most Intuitive)
This tool allows you to see the "web of relationships" for all objects in memory directly while the App is running.
Operation Steps:
-
Run the App: Run your project on a simulator or a physical device.
-
Reproduce the Path: Enter the interface suspected of having a memory leak (e.g., a complex detail page), then exit that interface. Repeat this 2–3 times.
-
Capture the Graph: In the Xcode debug bar at the bottom, click the Debug Memory Graph button (the icon with three small circles connected by lines).
-
Look for Anomalies:
- Observe the Left Panel: Xcode will mark objects it suspects of having a reference cycle with a purple exclamation mark.
- View the Reference Graph: Click an object, and the center panel will show who is holding it.
-
Identify the Loop:
- Look for lines that form a closed loop. For example:
ViewControllerClosure ContextViewController. - Solid lines represent Strong references, while dashed lines represent Weak or Unowned references.
- Look for lines that form a closed loop. For example:
2. Using Instruments - Leaks (Global Monitoring)
If you are unsure which interface is leaking, Instruments can perform a comprehensive scan.
Operation Steps:
-
Launch the Tool: Press
Command + Ito bring up Instruments and select the Leaks template. -
Start Recording: Click the red Record button in the top-left corner; the App will launch.
-
Operate the App: Use your App as you normally would. If a Red X appears on the Leaks track at the bottom, it means memory that cannot be reclaimed has been detected.
-
Analyze Details:
- Click the Cycles & Roots view at the bottom.
- Instruments will automatically identify the "Reference Rings" causing the leak.
- You can click a node and see exactly which line of code generated that reference in the Extended Detail pane on the right.
3. Complementary Strategies for the Two Tools
| Scenario | Recommended Tool | Reason |
|---|---|---|
| Locating leaks in a known page | Memory Graph | Faster response; intuitively shows weak vs strong directions. |
| Uncertain when the leak occurs | Leaks | Real-time monitoring; suitable for long-duration, wide-range path testing. |
| Analyzing Closure capture | Memory Graph | Clearly shows the relationship between malloc_block and object ownership. |
4. Practical Troubleshooting Tips
-
Malloc Stack Logging (Must-Have) :
Before debugging, it is highly recommended to go to Xcode
Scheme->Edit Scheme->Diagnosticsand check Malloc Stack (select Live Objects Only). Once enabled, clicking any object in the Memory Graph will allow you to see exactly on which line of code it was created. -
Search and Filter:
In the search box at the bottom-left of the Memory Graph, type your class name (e.g.,
MyViewController). If you can still find instances after the page has been closed, it is definitely being "hooked" by a strong reference cycle somewhere.