OC中如何调试野指针异常(EXC_BAD_ACCESS(code = ....))

来源:互联网 发布:输入字符串统计java 编辑:程序博客网 时间:2024/06/14 02:51

一哥们儿(__weak_Point)把自己在百度的面试题贴到了网上 面试题在百度面试题第八题 ,刚好当初公司面试我的时候也问到了这个问题。(当时没回答上来,最近又看到这个问题,就问总结了一下)

相信很多的人在工作和学习中都会遇到这个问题
这里写图片描述

图中的代码如下,注意代码是再非ARC中运行的

//注意,这些代码是在非ARC下运行的。    - (void)viewDidLoad {    [super viewDidLoad];    // Do any additional setup after loading the view, typically from a nib.    UIView * view1 = [[UIView alloc]init];    //View1指向对象的引用计数为0,对象销毁4    [self freeView:view1];    //view的对象此时已销毁,出现野指针,程序崩溃    [view1 setBackgroundColor:[UIColor orangeColor]];}//将传过来的对象release掉- (void)freeView:(NSObject *)obj{    [obj release];}

上面的代码很简单,一眼就可以看出什么地方出了问题,但是在实际的工作中,代码逻辑关系都很复杂,如果不小心释放了对象,出现这个问题,找起来是比较麻烦的。尤其是接管别人的代码。

这里就来说一下具体的结局方案

我们知道程序运行的时候,我们创建的对象都是存储在堆内存上的。我们可以通过监测堆内存上内存的变化,来监出现野指针的区域。这样就可以知道在哪里出现了问题。

Xcode 提供了运行程序时记录当前进程 堆内存变化的功能。现在我们打开这个功能,如下图所示。

这里写图片描述

这里写图片描述

然后我们运行程序,注意控制台输出。

这里写图片描述

malocHistory(3491,0x10d8ae300) malloc: stack logs being written into /tmp/stack-logs.3491.114ce0000.malocHistory.TJzvuk.indexmalocHistory(3491,0x10d8ae300) malloc: recording malloc and VM allocation stacks to disk using standard recordermalocHistory(3491,0x10d8ae300) malloc: process 3308 no longer exists, stack logs deleted from /tmp/stack-logs.3308.1126eb000.malocHistory.Kovf7r.index

控制台中说大概意思就是内存非配得历史已经开始记录,被写在了/tmp/stack-logs 文件夹下面。某个进程(process)已经不再存在了。记录他的mallocHistoy文件被删除。

我们到这个目录上看一下。(下面的代码是在我的pro上控制台中输入的,截图太慢了,==\\)

zhangxuongdeMBP:tmp zhangxudong$ cd /tmpzhangxuongdeMBP:tmp zhangxudong$ lsKSOutOfProcessFetcher.501.IW-ShwaXJwmHlkfc5wb2ZMHOaJY=NanoPreferencesSyncPlugInKit-Annotationscom.apple.CoreSimulator.SimDevice.6CAB348C-8E57-4F2A-A2B3-3326F2F84D8D.launchd_simcom.apple.CoreSimulator.SimDevice.D83EE71A-C375-44A4-8F5F-E704CAED94FE.launchd_simcom.apple.launchd.0u21btl7qCcom.apple.launchd.Vl0gfUy0kTcom.apple.launchd.YgEnK6wsOicom.apple.launchd.kXJa1h1Vr9com.apple.launchd.v3PwxXkHWXcom.sogou.inputmethodfm_sg_cloud_cache.v0.filemap.sogouime_3.2.0.69954_00000000_501stack-logs.3491.114ce0000.malocHistory.TJzvuk.index  #这个就是控制台中讲的文件zhangxuongdeMBP:tmp zhangxudong$ 

我们查看一下 这个文件

zhangxuongdeMBP:tmp zhangxudong$ cat stack-logs.3491.114ce0000.malocHistory.TJzvuk.index  U5??%?pU??ƚ?pU???0?U5?s?UU???k?UU???x?U???FbE?U????BT?????U???                                                               ?5U????C@uU????a%U???K?U????(?U????u(?U????u(UT????u(W????u(?W????uUUл???(UUл??u(eUл??u(5Uл??u(?Uл??u(?Uл??u(?Uл??u(uTл??u(Tл??u(?Tл??u(?Tл??u(?Tл??u(EWл??u(Wл??u(%Wл??u(?Wл??u(?Wл??u(UVл??u(eVл??u(5Vл??u(?Vл??u(?Vл??u(?Vл??u(uQл??u(Qл??u(?Qл??u(?Qл??u(?Qл??u(EPл??u(Pл??u(%Pл??u(?Pл??u(?Pл??u(USл??u(eSл??u(5Sл??u(?Sл??u(?Sл??u?Sл?? ERл?c eRл?MRл?ď 5Rл?ü?Rл?? ?Rл??0?Rл?Y_?Rл????Rл?  Rл?é??Rл?z2Rл?VN ?Rл?&EÅл??uöл??,EÅл?R??Rл??U%???U???o?U%?6? EÅл? eÅл????UU???????UU????? Åл?   ??Uu???Z?%Åл??% ?Åл???Åл?k% ?Åл??0?Åл?i??Åл?0?Rл??(?Åл?ÄU????(?Åл??;U???0?UU??ɻ?UU??>Huöл??US??>HUU???DUE??>HUS???D Uw??>HUE???D@U??>HUw???D?U???>HU???DUÅ??>HU????DU???6?U??>HÅ???DU???6?U??>HU???U???6U??>HU???DU???6?U??>HU???D?Åл?huöл?oXeÜл??)?Üл??X?^л??)EYл??XeYл??)?Yл??X?Yл??)EXл??XeXл??)?Xл??X?Xл??)E[л??Xe[л??)?[л??X?[л??)EZл??XeZл??)!?Zл??X?Zл??)uEл??XEл??)?Eл??X?Eл??)uDл??XDл??)Rл??X?Dл??)UGл??XuGл??)?Gл??X?Gл??)//........此处省略一万行 反正也看不懂.......................?ӻ?>j?ӻ???ߐ????U}???F5?????D???????????.??I???~??K?????zhangxuongdeMBP:tmp zhangxudong$ 

恩,这个文件我们是读不懂了。下面使用malloc_history 命令

查看一下命令帮助

zhangxuongdeMBP:images zhangxudong$ malloc_history --help[invalid usage]: no process id or name specified //无效的使用方法,没有制定有效的进程id或者进程名malloc_history: Displays/aggregates allocation histories in a processUsage: malloc_history <pid/partial-process-name> [options] <mode> [<address> ...] //显示进程中内存分配的历史 使用方法是  malloc_history <进程id/或者进程的名字> [操作选项] <mode> [内存地址]'mode' should be one of {-callTree, -allBySize, -allByCount, -allEvents, or one or more addresses}    -allBySize                        [mode]    -allByCount                       [mode]    -allEvents                        [mode]    -callTree                         [mode]    -highWaterMark                        -showContent                      (-calltree only)    -invert                           (-calltree only)    -ignoreThreads                    (-calltree only)    -collapseRecursion                (-calltree only)    -chargeSystemLibraries            (-calltree only)    -consolidateAllBySymbol           (-calltree only)    -consolidateSystemFramesBySymbol  (-calltree only)zhangxuongdeMBP:images zhangxudong$ 

进程名,可以通过上面控制台的输出知道,3491。
对应的内存地址,从前前面已经知道是 0x00007fcbbd9345f0

从控制台中查询。

zhangxuongdeMBP:images zhangxudong$ malloc_history 3491 0x00007fcbbd9345f0malloc_history Report Version:  2.0Invalid connection: com.apple.coresymbolicationdALLOC 0x7fcbbd9345f0-0x7fcbbd93471f [size=304]: thread_10d8ae300 |start | main | UIApplicationMain | -[UIApplication _run] | CFRunLoopRunSpecific | __CFRunLoopRun | __CFRunLoopDoBlocks | __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ | __31-[FBSSerialQueue performAsync:]_block_invoke_2 | -[UIApplication workspaceDidEndTransaction:] | -[UIApplication _runWithMainScene:transitionContext:completion:] | -[UIApplication _createStatusBarWithRequestedStyle:orientation:hidden:] | -[UIWindow _initWithOrientation:] | -[UIView init] | -[UIStatusBarWindow initWithFrame:] | -[UIWindow _initWithFrame:debugName:scene:attached:] | -[UIApplication _updateCurrentStatusBarViewControllerAppearance] | -[UIApplication _setStatusBarStyle:animationParameters:] | -[UIStatusBar _requestStyleAttributes:animationParameters:] | -[UIStatusBar _prepareToSetStyle:animation:] | +[UIView(Animation) performWithoutAnimation:] | __44-[UIStatusBar _prepareToSetStyle:animation:]_block_invoke | -[UIStatusBarForegroundView setStatusBarData:actions:animated:] | -[UIStatusBarForegroundView _setStatusBarData:actions:animated:] | -[UIStatusBarForegroundView _reflowItemViewsWithDuration:preserveHistory:] | -[UIStatusBarForegroundView _computeVisibleItemsPreservingHistory:] | -[UIStatusBarLayoutManager distributeOverlap:amongItems:] | -[UIStatusBarServiceItemView addContentOverlap:] | -[UIStatusBarServiceItemView updateContentsAndWidth] | -[UIStatusBarServiceItemView _contentsImageFromString:withWidth:letterSpacing:] | -[UIStatusBarForegroundStyleAttributes imageWithText:ofItemType:forWidth:lineBreakMode:letterSpacing:textAlignment:style:withLegibilityStyle:legibilityStrength:] | -[NSString(UIStringDrawingLegacy) _legacy_sizeWithFont:forWidth:lineBreakMode:letterSpacing:] | -[NSString(NSExtendedStringDrawing) boundingRectWithSize:options:attributes:context:] | __NSStringDrawingEngine | CTLineCreateTruncatedLineWithTokenHandler | TTruncator::EndTruncate(double, __CTRun const* (__CTLine const*, CFRange*, __CFDictionary const*) block_pointer) | TTruncator::CreateToken(CFRange&, __CTRun const* (__CTLine const*, CFRange*, __CFDictionary const*) block_pointer) | ____NSStringDrawingEngine_block_invoke_2 | CTLineCreateWithAttributedString | TTypesetterAttrString::TTypesetterAttrString(__CFAttributedString const*) | TTypesetterAttrString::Initialize(__CFAttributedString const*) | TGlyphEncoder::EncodeChars(CFRange, TAttributes const&, TGlyphList<TDeletedGlyphIndex>&, TGlyphEncoder::Fallbacks) | _CFRuntimeCreateInstance | malloc_zone_malloc ----FREE  0x7fcbbd9345f0-0x7fcbbd93471f [size=304]: thread_10d8ae300 |start | main | UIApplicationMain | -[UIApplication _run] | CFRunLoopRunSpecific | __CFRunLoopRun | __CFRunLoopDoBlocks | __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ | __31-[FBSSerialQueue performAsync:]_block_invoke_2 | -[UIApplication workspaceDidEndTransaction:] | -[UIApplication _runWithMainScene:transitionContext:completion:] | -[UIApplication _createStatusBarWithRequestedStyle:orientation:hidden:] | -[UIWindow _initWithOrientation:] | -[UIView init] | -[UIStatusBarWindow initWithFrame:] | -[UIWindow _initWithFrame:debugName:scene:attached:] | -[UIApplication _updateCurrentStatusBarViewControllerAppearance] | -[UIApplication _setStatusBarStyle:animationParameters:] | -[UIStatusBar _requestStyleAttributes:animationParameters:] | -[UIStatusBar _prepareToSetStyle:animation:] | +[UIView(Animation) performWithoutAnimation:] | __44-[UIStatusBar _prepareToSetStyle:animation:]_block_invoke | -[UIStatusBarForegroundView setStatusBarData:actions:animated:] | -[UIStatusBarForegroundView _setStatusBarData:actions:animated:] | -[UIStatusBarForegroundView _reflowItemViewsWithDuration:preserveHistory:] | -[UIStatusBarForegroundView _computeVisibleItemsPreservingHistory:] | -[UIStatusBarLayoutManager distributeOverlap:amongItems:] | -[UIStatusBarServiceItemView addContentOverlap:] | -[UIStatusBarServiceItemView updateContentsAndWidth] | -[UIStatusBarServiceItemView _contentsImageFromString:withWidth:letterSpacing:] | -[UIStatusBarForegroundStyleAttributes imageWithText:ofItemType:forWidth:lineBreakMode:letterSpacing:textAlignment:style:withLegibilityStyle:legibilityStrength:] | -[UIStatusBarForegroundStyleAttributes drawText:forWidth:lineBreakMode:letterSpacing:textAlignment:style:textSize:textHeight:] | -[NSString(UIStringDrawingLegacy) _legacy_drawAtPoint:forWidth:withFont:lineBreakMode:letterSpacing:includeEmoji:] | -[NSAttributedString(NSExtendedStringDrawing) drawWithRect:options:context:] | __NSStringDrawingEngine | CTLineCreateTruncatedLineWithTokenHandler | TTruncator::EndTruncate(double, __CTRun const* (__CTLine const*, CFRange*, __CFDictionary const*) block_pointer) | TTruncator::CreateToken(CFRange&, __CTRun const* (__CTLine const*, CFRange*, __CFDictionary const*) block_pointer) | ____NSStringDrawingEngine_block_invoke_2 | CFRelease | malloc_zone_free ALLOC 0x7fcbbd9345f0-0x7fcbbd934647 [size=88]: thread_10d8ae300 |start | main | UIApplicationMain | -[UIApplication _run] | CFRunLoopRunSpecific | __CFRunLoopRun | __CFRunLoopDoBlocks | __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ | __31-[FBSSerialQueue performAsync:]_block_invoke_2 | -[UIApplication workspaceDidEndTransaction:] | -[UIApplication _runWithMainScene:transitionContext:completion:] | -[UIApplication _createStatusBarWithRequestedStyle:orientation:hidden:] | -[UIWindow _initWithOrientation:] | -[UIView init] | -[UIStatusBarWindow initWithFrame:] | -[UIWindow _initWithFrame:debugName:scene:attached:] | -[UIApplication _updateCurrentStatusBarViewControllerAppearance] | -[UIApplication _setStatusBarStyle:animationParameters:] | -[UIStatusBar _requestStyleAttributes:animationParameters:] | -[UIStatusBar _prepareToSetStyle:animation:] | +[UIView(Animation) performWithoutAnimation:] | __44-[UIStatusBar _prepareToSetStyle:animation:]_block_invoke | -[UIStatusBarForegroundView setStatusBarData:actions:animated:] | -[UIStatusBarForegroundView _setStatusBarData:actions:animated:] | -[UIStatusBarForegroundView _reflowItemViewsWithDuration:preserveHistory:] | -[UIStatusBarForegroundView _computeVisibleItemsPreservingHistory:] | -[UIStatusBarLayoutManager distributeOverlap:amongItems:] | -[UIStatusBarServiceItemView addContentOverlap:] | -[UIStatusBarServiceItemView updateContentsAndWidth] | -[UIStatusBarServiceItemView _contentsImageFromString:withWidth:letterSpacing:] | -[UIStatusBarForegroundStyleAttributes imageWithText:ofItemType:forWidth:lineBreakMode:letterSpacing:textAlignment:style:withLegibilityStyle:legibilityStrength:] | -[UIStatusBarForegroundStyleAttributes drawText:forWidth:lineBreakMode:letterSpacing:textAlignment:style:textSize:textHeight:] | -[NSString(UIStringDrawingLegacy) _legacy_drawAtPoint:forWidth:withFont:lineBreakMode:letterSpacing:includeEmoji:] | -[NSAttributedString(NSExtendedStringDrawing) drawWithRect:options:context:] | __NSStringDrawingEngine | CTLineDraw | TRun::DrawGlyphs(CGContext*, CFRange) const | CGGStateSetFont | maybe_copy_text_state | malloc | malloc_zone_malloc ----FREE  0x7fcbbd9345f0-0x7fcbbd934647 [size=88]: thread_10d8ae300 |start | main | UIApplicationMain | -[UIApplication _run] | CFRunLoopRunSpecific | __CFRunLoopRun | __CFRunLoopDoBlocks | __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ | __31-[FBSSerialQueue performAsync:]_block_invoke_2 | -[UIApplication workspaceDidEndTransaction:] | -[UIApplication _runWithMainScene:transitionContext:completion:] | -[UIApplication _createStatusBarWithRequestedStyle:orientation:hidden:] | -[UIWindow _initWithOrientation:] | -[UIView init] | -[UIStatusBarWindow initWithFrame:] | -[UIWindow _initWithFrame:debugName:scene:attached:] | -[UIApplication _updateCurrentStatusBarViewControllerAppearance] | -[UIApplication _setStatusBarStyle:animationParameters:] | -[UIStatusBar _requestStyleAttributes:animationParameters:] | -[UIStatusBar _prepareToSetStyle:animation:] | +[UIView(Animation) performWithoutAnimation:] | __44-[UIStatusBar _prepareToSetStyle:animation:]_block_invoke | -[UIStatusBarForegroundView setStatusBarData:actions:animated:] | -[UIStatusBarForegroundView _setStatusBarData:actions:animated:] | -[UIStatusBarForegroundView _reflowItemViewsWithDuration:preserveHistory:] | -[UIStatusBarForegroundView _computeVisibleItemsPreservingHistory:] | -[UIStatusBarLayoutManager distributeOverlap:amongItems:] | -[UIStatusBarServiceItemView addContentOverlap:] | -[UIStatusBarServiceItemView updateContentsAndWidth] | -[UIStatusBarServiceItemView _contentsImageFromString:withWidth:letterSpacing:] | -[UIStatusBarForegroundStyleAttributes imageWithText:ofItemType:forWidth:lineBreakMode:letterSpacing:textAlignment:style:withLegibilityStyle:legibilityStrength:] | PopContext | CFRelease | context_finalize | CGGStackRelease | CGGStackReset | CGGStateRelease | free ALLOC 0x7fcbbd9345f0-0x7fcbbd9346e7 [size=248]: thread_10d8ae300 |start | main | UIApplicationMain | -[UIApplication _run] | CFRunLoopRunSpecific | __CFRunLoopRun | __CFRunLoopDoBlocks | __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ | __31-[FBSSerialQueue performAsync:]_block_invoke_2 | -[UIApplication workspaceDidEndTransaction:] | -[UIApplication _runWithMainScene:transitionContext:completion:] | -[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] | -[UIWindow makeKeyAndVisible] | -[UIWindow _setHidden:forced:] | -[UIWindow addRootViewControllerViewIfPossible] | -[UIViewController view] | -[UIViewController loadViewIfRequired] | -[UIViewController loadView] | -[UIViewController _loadViewFromNibNamed:bundle:] | -[UINib instantiateWithOwner:options:] | -[UINib unarchiverForInstantiatingReturningError:] | -[UINibDecoder initForReadingWithData:error:] | -[UINibDecoder validateAndIndexData:error:] | -[UINibDecoder validateAndIndexObjects:length:] | calloc | malloc_zone_calloc ----FREE  0x7fcbbd9345f0-0x7fcbbd9346e7 [size=248]: thread_10d8ae300 |start | main | UIApplicationMain | -[UIApplication _run] | CFRunLoopRunSpecific | __CFRunLoopRun | __CFRunLoopDoBlocks | __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ | __31-[FBSSerialQueue performAsync:]_block_invoke_2 | -[UIApplication workspaceDidEndTransaction:] | -[UIApplication _runWithMainScene:transitionContext:completion:] | -[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] | -[UIWindow makeKeyAndVisible] | -[UIWindow _setHidden:forced:] | -[UIWindow addRootViewControllerViewIfPossible] | -[UIViewController view] | -[UIViewController loadViewIfRequired] | -[UIViewController loadView] | -[UIViewController _loadViewFromNibNamed:bundle:] | objc_object::sidetable_release(bool) | -[UINib dealloc] | objc_object::sidetable_release(bool) | -[UINibStorage dealloc] | objc_object::sidetable_release(bool) | -[UINibDecoder dealloc] | free ALLOC 0x7fcbbd9345f0-0x7fcbbd9346ff [size=272]: thread_10d8ae300 |start | main | UIApplicationMain | -[UIApplication _run] | CFRunLoopRunSpecific | __CFRunLoopRun | __CFRunLoopDoBlocks | __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ | __31-[FBSSerialQueue performAsync:]_block_invoke_2 | -[UIApplication workspaceDidEndTransaction:] | -[UIApplication _runWithMainScene:transitionContext:completion:] | -[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] | -[UIWindow makeKeyAndVisible] | -[UIWindow _setHidden:forced:] | -[UIWindow addRootViewControllerViewIfPossible] | -[UIViewController view] | -[UIViewController loadViewIfRequired] | -[ViewController viewDidLoad] | _objc_rootAlloc | class_createInstance | calloc | malloc_zone_calloc ----FREE  0x7fcbbd9345f0-0x7fcbbd9346ff [size=272]: thread_10d8ae300 |start | main | UIApplicationMain | -[UIApplication _run] | CFRunLoopRunSpecific | __CFRunLoopRun | __CFRunLoopDoBlocks | __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ | __31-[FBSSerialQueue performAsync:]_block_invoke_2 | -[UIApplication workspaceDidEndTransaction:] | -[UIApplication _runWithMainScene:transitionContext:completion:] | -[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] | -[UIWindow makeKeyAndVisible] | -[UIWindow _setHidden:forced:] | -[UIWindow addRootViewControllerViewIfPossible] | -[UIViewController view] | -[UIViewController loadViewIfRequired] | -[ViewController viewDidLoad] | -[ViewController freeView:] | -[UIView dealloc] | -[UIResponder dealloc] | object_dispose | free zhangxuongdeMBP:images zhangxudong$ 

从这些输出中我们可以知道,堆这个内存的使用情况,从哪个方法中使用。他们的使用历史。

代码确实比较多,alloc(开辟地址) 和 free(释放地址) 成对出现 ,内存已经被释放了。注意最后一个free 有一句话 -[ViewController freeView:] 调用了个方法。之后 -[UIView dealloc] 。
现在已经确定了,问题所在。

1 0