iOS 16下ViewController dealloc崩溃问题(Xcode14升级后出现)
Xcode 14下登录后偶发僵尸对象崩溃排查方案
问题背景
- 应用在iOS 15 + Xcode 13环境运行正常,切换到Xcode 14后,登录后出现偶发崩溃
- 已开启僵尸对象检测:操作路径为
Edit Schemes -> Diagnostics,勾选Zombie objects选项
崩溃日志
Thread 0 Crashed: 0 libobjc.A.dylib 0x00000001b4a1e820 objc_msgSend + 32 1 UIKitCore 0x00000001bdbe74a4 -[UIViewController dealloc] + 772 (UIViewController.m:3102) 2 UIKitCore 0x00000001bdbe50cc -[UINavigationController dealloc] + 308 (UINavigationController.m:786) 3 CoreFoundation 0x00000001bb9e2734 __RELEASE_OBJECTS_IN_THE_ARRAY__ + 116 (NSCollectionAux.h:70) 4 CoreFoundation 0x00000001bb981b94 -[__NSFrozenArrayM dealloc] + 124 (NSCopyOnWrite.h:229) 5 UIKitCore 0x00000001be1539ec -[UIMoreListController .cxx_destruct] + 76 (UIMoreListController.m:58) 6 libobjc.A.dylib 0x00000001b4a1e0a4 object_cxxDestructFromClass(objc_object*, objc_class*) + 116 (objc-class.mm:456) 7 libobjc.A.dylib 0x00000001b4a22e00 objc_destructInstance + 80 (objc-runtime-new.mm:8628) 8 libobjc.A.dylib 0x00000001b4a2c4fc _objc_rootDealloc + 80 (NSObject.mm:2138) 9 UIKitCore 0x00000001bdbe78d8 -[UIResponder dealloc] + 124 (UIResponder.m:184) 10 UIKitCore 0x00000001bdbe75dc -[UIViewController dealloc] + 1084 (UIViewController.m:3133) 11 libobjc.A.dylib 0x00000001b4a1e0a4 object_cxxDestructFromClass(objc_object*, objc_class*) + 116 (objc-class.mm:456) 12 libobjc.A.dylib 0x00000001b4a22e00 objc_destructInstance + 80 (objc-runtime-new.mm:8628) 13 libobjc.A.dylib 0x00000001b4a2c4fc _objc_rootDealloc + 80 (NSObject.mm:2138) 14 UIKitCore 0x00000001bdbe78d8 -[UIResponder dealloc] + 124 (UIResponder.m:184) 15 UIKitCore 0x00000001bdbe75dc -[UIViewController dealloc] + 1084 (UIViewController.m:3133) 16 UIKitCore 0x00000001bdbe50cc -[UINavigationController dealloc] + 308 (UINavigationController.m:786) 17 libobjc.A.dylib 0x00000001b4a1e1d4 AutoreleasePoolPage::releaseUntil(objc_object**) + 196 (NSObject.mm:938) 18 libobjc.A.dylib 0x00000001b4a21bdc objc_autoreleasePoolPop + 256 (NSObject.mm:2186) 19 UIKitCore 0x00000001bdb87444 -[_UIAfterCACommitBlock run] + 92 (_UIAfterCACommitQueue.m:155) 20 UIKitCore 0x00000001bdb87364 -[_UIAfterCACommitQueue flush] + 168 (_UIAfterCACommitQueue.m:228) 21 UIKitCore 0x00000001bdb87278 _runAfterCACommitDeferredBlocks + 496 (UIApplication.m:3249) 22 UIKitCore 0x00000001bda25ee4 _cleanUpAfterCAFlushAndRunDeferredBlocks + 108 (UIApplication.m:3213) 23 UIKitCore 0x00000001bdee4608 _UIApplicationFlushCATransaction + 72 (UIApplication.m:3290) 24 UIKitCore 0x00000001be034e00 _UIUpdateSequenceRun + 84 (_UIUpdateSequence.mm:114) 25 UIKitCore 0x00000001be698944 schedulerStepScheduledMainSection + 144 (_UIUpdateScheduler.m:1015) 26 UIKitCore 0x00000001be697ea0 runloopSourceCallback + 92 (_UIUpdateScheduler.m:1116) 27 CoreFoundation 0x00000001bba4c208 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 28 (CFRunLoop.c:1957) 28 CoreFoundation 0x00000001bba58864 __CFRunLoopDoSource0 + 176 (CFRunLoop.c:2001) 29 CoreFoundation 0x00000001bb9dd6c8 __CFRunLoopDoSources0 + 244 (CFRunLoop.c:2038) 30 CoreFoundation 0x00000001bb9f31c4 __CFRunLoopRun + 828 (CFRunLoop.c:2953) 31 CoreFoundation 0x00000001bb9f84dc CFRunLoopRunSpecific + 612 (CFRunLoop.c:3418) 32 GraphicsServices 0x00000001f6c5835c GSEventRunModal + 164 (GSEvent.c:2196) 33 UIKitCore 0x00000001bdd8437c -[UIApplication _run] + 888 (UIApplication.m:3773) 34 UIKitCore 0x00000001bdd83fe0 UIApplicationMain + 340 (UIApplication.m:5363)
排查思路与方案
从崩溃栈分析,崩溃属于僵尸对象访问(即调用了已被释放对象的方法),核心触发点在UIMoreListController和UINavigationController的释放流程中,结合Xcode14的环境变化,可从以下方向排查:
1. 检查导航控制器的内存管理
- 排查自定义
UINavigationController的dealloc方法,确认是否存在调用已释放对象的逻辑,比如未清空的代理、block或KVO监听 - 检查是否存在循环引用:比如子控制器通过强引用持有导航控制器,导致对象无法正常释放
2. 排查TabBar相关逻辑
- 登录后跳转TabBar时,是否对
UIMoreListController(TabBar默认的“更多”页面控制器)做了自定义修改,比如修改导航栏、添加子控制器时的内存处理不当 - 确认TabBar控制器的子控制器数组是否被意外修改或提前释放
3. 适配Xcode14的编译变化
- Xcode14默认启用了更严格的ARC规则,检查之前被ARC兼容的内存问题是否现在触发崩溃
- 确认是否使用了iOS16+的新API但未做版本判断,导致iOS15环境下出现内存异常
4. 强化调试手段
- 开启
Malloc Stack Logging:在Edit Schemes -> Diagnostics中勾选Malloc Stack,重现崩溃后用malloc_history命令查看对象的分配/释放完整栈 - 手动设置
NSZombieEnabled环境变量:在Scheme的Environment Variables中添加NSZombieEnabled=YES,崩溃时会打印具体被重复释放的对象信息 - 在关键控制器的
dealloc方法中添加日志,跟踪对象释放顺序是否符合预期
内容的提问来源于stack exchange,提问作者OMANSAK
相关产品推荐
相关产品推荐

