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

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

相信很多的人在工作和学习中都会遇到这个问题
OC中如何调试野指针异常(EXC_BAD_ACCESS(code = ....))_第1张图片

图中的代码如下,注意代码是再非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 提供了运行程序时记录当前进程 堆内存变化的功能。现在我们打开这个功能,如下图所示。

OC中如何调试野指针异常(EXC_BAD_ACCESS(code = ....))_第2张图片

OC中如何调试野指针异常(EXC_BAD_ACCESS(code = ....))_第3张图片

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

OC中如何调试野指针异常(EXC_BAD_ACCESS(code = ....))_第4张图片

malocHistory(3491,0x10d8ae300) malloc: stack logs being written into /tmp/stack-logs.3491.114ce0000.malocHistory.TJzvuk.index
malocHistory(3491,0x10d8ae300) malloc: recording malloc and VM allocation stacks to disk using standard recorder
malocHistory(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 /tmp
zhangxuongdeMBP:tmp zhangxudong$ ls
KSOutOfProcessFetcher.501.IW-ShwaXJwmHlkfc5wb2ZMHOaJY=
NanoPreferencesSync
PlugInKit-Annotations
com.apple.CoreSimulator.SimDevice.6CAB348C-8E57-4F2A-A2B3-3326F2F84D8D.launchd_sim
com.apple.CoreSimulator.SimDevice.D83EE71A-C375-44A4-8F5F-E704CAED94FE.launchd_sim
com.apple.launchd.0u21btl7qC
com.apple.launchd.Vl0gfUy0kT
com.apple.launchd.YgEnK6wsOi
com.apple.launchd.kXJa1h1Vr9
com.apple.launchd.v3PwxXkHWX
com.sogou.inputmethod
fm_sg_cloud_cache.v0.filemap.sogouime_3.2.0.69954_00000000_501
stack-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 process
Usage: malloc_history  [options]  [
...] //显示进程中内存分配的历史 使用方法是 malloc_history <进程id/或者进程的名字> [操作选项] [内存地址] '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 0x00007fcbbd9345f0
malloc_history Report Version:  2.0
Invalid connection: com.apple.coresymbolicationd
ALLOC 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&, 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] 。
现在已经确定了,问题所在。

你可能感兴趣的:(个人总结)