什么是 Zombie Objects?
当开启 “Zombie Objects” 后,对象不会立即释放,而是会被转成特殊的 “NSZombie” 类型。这样,当错误地访问这个已释放对象时,不会直接崩溃,而是输出更清晰的调试信息,比如:
-[MyClass doSomething]: message sent to deallocated instance 0x123456
这比原始的报错信息:
Thread 3: EXC_BAD_ACCESS (code=2, address=0x...)
要清晰很多。
开启Zombie Objects
1、打开Xcode项目。
2、点顶部菜单:Product > Scheme > Edit Scheme。

3、在左侧选中Run(运行目标)。
4、点击 Diagnostics。
5、勾选 Memory Management – Zombie Objects选项。

运行程序
开启Zombie Objects后,运行发生EXC_BAD_ACCESS的程序,Xcode控制台会输出:
*** -[MyClass doSomething]: message sent to deallocated instance 0x123abc
还可以同时启用以下选项:
1、Malloc Scribble:释放内存时填充 0xAA,帮你更早发现非法使用。
2、Malloc Guard Edges:在 malloc 分配两端放 guard 区域,用于发现越界读写。
3、Malloc Stack Logging:记录 malloc 调用栈,用 Instruments 查看谁分配的内存。

这些工具组合起来,对付内存问题非常高效。
注意事项
性能下降:调试用,别在发布版本开启。
内存占用会变高:僵尸对象不会释放,适合定位问题,而不是持续使用。
常用问题场景
1、delegate 没设置为 weak。
2、对象释放后仍访问。
3、捕获循环或异步访问错误引用。
4、Combine、GCD、async/await 捕获了生命周期错误对象。
总结
Zombie Objects(僵尸对象)可以检测EXC_BAD_ACCESS的崩溃问题,并输出详细的信息。
对于无法通过Zombie Objects检测的崩溃,可以尝试使用Task { @MainActor in }包裹崩溃的代码字段:
Task { @MainActor in
// 代码行
}
因为某些对象的生命周期或线程访问不安全,违反了线程要求,也是造成EXC_BAD_ACCESS的崩溃原因。
扩展知识
无法捕获崩溃的问题
如果开启Zombie Objects后,仍然出现EXC_BAD_ACCESS 并没有显示类似:
*** -[MyClass method]: message sent to deallocated instance 0x...
说明,这个崩溃不是由于「消息发送给已释放对象(Zombie)」引起的,而是属于以下几种情况之一:
一、C/C++ 层级或 CoreFoundation 层级的内存访问(无法被 Zombie 捕捉)
Zombie 机制只对 Objective-C 对象的方法调用生效。
如果崩溃发生在:
1)CoreFoundation (CFArray、CFUUID 等);
2)CoreGraphics、CoreMedia、AVFoundation 等底层 C-API;
3)使用了 C 指针(如 UnsafeMutablePointer)访问内存;
4)Metal 或某些底层系统库返回已释放对象;
那 Zombie 就无法catch 到具体对象或类型。
二、非消息调用(即不是调用 [obj method])引起的访问
比如直接访问了已释放对象的内存地址或成员变量,而不是通过方法发送消息,也不会被 Zombie 捕捉:
let name = someObject.name // 直接访问属性
如果 someObject 已释放,这也只会触发 EXC_BAD_ACCESS,Zombie 不会输出任何信息。