1、野指针问题
【exc_bad_access (sigsegv) / kern_invalid_address]
possible zombie in call: function: objc_releaseparam 1: 0x157f2a740 originated at or in a subcall of unknown, cannot find symb
如有以下崩溃栈可以怀疑是在dealloc
中直接或间接使用了@try{} @catch{}
2、崩溃栈
libobjc.a.dylib _objc_release() corefoundation -[__nsdictionaryi dealloc]() corefoundation -[nsexception dealloc]() libobjc.a.dylib autoreleasepoolpage::releaseuntil(objc_object**)() libobjc.a.dylib _objc_autoreleasepoolpop() ...... ......
3、场景复现代码
#import "viewcontroller.h" @interface testexpectionobj : nsobject @end @implementation testexpectionobj - (void)dealloc { @try { [self setvalue:@"test" forkey:@"testkey"]; } @catch (nsexception *exception) { nslog(@"%@", exception); } } @end @implementation viewcontroller - (void)viewdidload { [super viewdidload]; // do any additional setup after loading the view. [testexpectionobj new]; } @end
4、问题分析
在dealloc
使用try-catch
并触发catch时,会生成nsexception
对象,exception结构如下
exception : nsexception { userinfo: nsdictionary { nstargetobjectuserinfokey = "<testexpectionobj: 0x6000038ac3e0>"; } }
故exception
会强引用testexpectionobj
对象,并且exception
一般都是类方法生成会自动加入到autoreleasepool
,所以dealloc
执行完后testexpectionobj
对象已经释放(因为在dealloc
方法中在强引用当前对象没法终止当前对象的释放,引用计数增加与否已无意义),所以exception.userinfo
中的testexpectionobj
对变成野对象。
当autoreleasepool
到达周期释放时就对调用release exception & userinfo,字典userinfo
释放时会也会相应的释放key/value,故nstargetobjectuserinfokey = "<testexpectionobj: 0x6000038ac3e0>"
又调用一次release
,因为之前已经dealloc
完毕,所以这次就会触发重复释放崩溃引起野指针问题,
但如果exception
在testexpectionobj
对象的dealloc
方法执行完之前释放就不会出现问题。
5、上报可能引起野指针崩溃栈
#import <jrswizzle/jrswizzle.h> @implementation nsexception (exceptiontestsunztobj) + (void)load { static dispatch_once_t oncetoken; dispatch_once(&oncetoken, ^{ [self jr_swizzlemethod:nsselectorfromstring(@"dealloc") withmethod:@selector(intercept_dealloc) error:nil]; }); } - (void)intercept_dealloc { bool iscontaindealloc = no; nsmutablestring *symblos = [nsmutablestring string]; for (nsstring *sym in self.callstacksymbols) { [symblos appendformat:@"%@\n", sym]; if ([sym containsstring:@" dealloc]"]) { iscontaindealloc = yes; } } // 把 symblos上报给自己的apm平台 [apm report:@"ttreportexceptioncallstacksymbols" withvalue:symblos]; [apm report:@"ttreportexceptionreason" withvalue:self.reason?:@"null"]; if (iscontaindealloc) { // 本地log打印,需符号化 ttlocallog("nsexception:throws:dealloc:ttreport", { @"name": self.name?:@"", @"reason": self.reason?:@"", @"callstacksymbols": symblos }); // 延迟保证数据写完在释放 __unsafe_unretained nsexception *demoself = self; dispatch_after(dispatch_time(dispatch_time_now, (int64_t)(1.0 * nsec_per_sec)), dispatch_get_main_queue(), ^{ [demoself intercept_dealloc]; }); return; } [self intercept_dealloc]; } @end
注:在dealloc
中使用@try{} @catch{}
可能会引起难以排查的野指针崩溃
使用@try-@catch
后
[<testexpectionobj 0x600000714220> setvalue:forundefinedkey:]: this class is not key value coding-compliant for the key testkey. ( 0 corefoundation 0x0000000102a93604 __exceptionpreprocess + 242 1 libobjc.a.dylib 0x0000000102943a45 objc_exception_throw + 48 2 corefoundation 0x0000000102a9329c -[nsexception init] + 0 3 foundation 0x00000001034f2354 -[nsobject(nskeyvaluecoding) setvalue:forkey:] + 315 4 expectiondemo 0x00000001023cae52 -[testexpectionobj dealloc] + 50 5 libobjc.a.dylib 0x00000001029417b7 _zn11objc_object17sidetable_releaseebb + 177 6 expectiondemo 0x00000001023caf58 -[viewcontroller viewdidload] + 72 7 uikitcore 0x000000010f3ce3bc -[uiviewcontroller _sendviewdidloadwithappearanceproxyobjecttaggingenabled] + 88 8 uikitcore 0x000000010f3d2dbf -[uiviewcontroller loadviewifrequired] + 1193 9 uikitcore 0x000000010f3d319a -[uiviewcontroller view] + 27 10 uikitcore 0x000000010fbdb00a -[uiwindow addrootviewcontrollerviewifpossible] + 305 11 uikitcore 0x000000010fbda6fe -[uiwindow _updatelayerorderingandsetlayerhidden:actionblock:] + 230 12 uikitcore 0x000000010fbdb6d6 -[uiwindow _sethidden:forced:] + 409 13 uikitcore 0x000000010fbee204 -[uiwindow _mainqueue_makekeyandvisible] + 47 14 uikitcore 0x000000010fe605f6 -[uiwindowscene _makekeyandvisibleifneeded] + 202 15 uikitcore 0x000000010ef0fb8f +[uiscene _sceneforfbsscene:create:withsession:connectionoptions:] + 1591 16 uikitcore 0x000000010fb98fbd -[uiapplication _connectuiscenefromfbsscene:transitioncontext:] + 1299 17 uikitcore 0x000000010fb99471 -[uiapplication workspace:didcreatescene:withtransitioncontext:completion:] + 301 18 uikitcore 0x000000010f613afe -[uiapplicationsceneclientagent scene:didinitializewithevent:completion:] + 355 19 frontboardservices 0x0000000107090cdd -[fbsscene _calloutqueue_agent_didcreatewithtransitioncontext:completion:] + 415 20 frontboardservices 0x00000001070bd216 __94-[fbsworkspacescenesclient createwithsceneid:groupid:parameters:transitioncontext:completion:]_block_invoke.180 + 102 21 frontboardservices 0x000000010709f0ef -[fbsworkspace _calloutqueue_executecalloutfromsource:withblock:] + 209 22 frontboardservices 0x00000001070bcdf5 __94-[fbsworkspacescenesclient createwithsceneid:groupid:parameters:transitioncontext:completion:]_block_invoke + 352 23 libdispatch.dylib 0x0000000103c0ba5b _dispatch_client_callout + 8 24 libdispatch.dylib 0x0000000103c0e93b _dispatch_block_invoke_direct + 295 25 frontboardservices 0x00000001070e3da3 __fbsserialqueue_is_calling_out_to_a_block__ + 30 26 frontboardservices 0x00000001070e3c99 -[fbsserialqueue _targetqueue_performnextifpossible] + 174 27 frontboardservices 0x00000001070e3dcb -[fbsserialqueue _performnextfromrunloopsource] + 19 28 corefoundation 0x0000000102a004a7 __cfrunloop_is_calling_out_to_a_source0_perform_function__ + 17 29 corefoundation 0x0000000102a0039f __cfrunloopdosource0 + 180 30 corefoundation 0x00000001029ff8ce __cfrunloopdosources0 + 340 31 corefoundation 0x00000001029f9f68 __cfrunlooprun + 871 32 corefoundation 0x00000001029f9704 cfrunlooprunspecific + 562 33 graphicsservices 0x00000001071e3c8e gseventrunmodal + 139 34 uikitcore 0x000000010fb9765a -[uiapplication _run] + 928 35 uikitcore 0x000000010fb9c2b5 uiapplicationmain + 101 36 expectiondemo 0x00000001023cb1be main + 110 37 dyld 0x00000001025e6f21 start_sim + 10 38 ??? 0x00000001091ce4fe 0x0 + 4447855870 )
这种崩溃信息使用nssetuncaughtexceptionhandler()
是抓不到的
以上就是ios开发 try-catch引起的野指针问题排查的详细内容,更多关于ios开发try-catch野指针的资料请关注代码网其它相关文章!
发表评论