您的位置:首页 > 移动开发 > IOS开发

ios调度EXC_BAD_ACCESS

2015-11-10 10:32 211 查看
iOS开发,最郁闷的莫过于程序毫无征兆地就崩溃了,用bt命令打出调用栈,给出的是一堆系统EXC_BAD_ACCESS的信息,根本没办法定位问题出现在哪里。 首先说一下 EXC_BAD_ACCESS 这个错误,可以这么说,90%的错误来源在于对一个已经释放的对象进行release操作。举一个简单的例子来说明吧,首先看一段Java代码:

复制代码代码如下:

public class Test{ 

public static void main(String[] args){ 

String s = "This is a test string"; 

s = s.substring(s.indexOf("a"),(s.length())); 

System.out.println(s); 



}

通常这样的崩溃出现,原因一般就是:调用了已经释放的内存空间,或者说重复释放了某个地址空间。而怎样定位到这个地址呢,可以通过编辑xcode的scheme,添加如下标记位,让系统把错误地址打印出来,如图:

(通过Product->Scheme->Edit Scheme进入下面编辑页面,选中Arguments tab,增加标计位NSZombieEnabled设为YES)



这样,但崩溃出现,系统会出现以下提示信息:

2013-06-23 00:45:20.479 *** -[__NSArrayM addObject:]: message sent to deallocated instance 0x7179910

可见崩溃原因是内存地址[b]0x7179910被重复释放了。[/b]

Objective-C 这段代码有三个致命问题:1、内存泄露;2、错误释放;3、造成 EXC_BAD_ACCESS 错误。

如果崩溃是发生在当前调用栈,通过上面的做法,系统就会把崩溃原因定位到具体代码中。但是,如果崩溃不在当前调用栈,系统就仅仅只能把崩溃地址告诉我们,而没办法定位到具体代码,这样我们也没法去修改错误。这时就可以修改scheme,让xcode记录每个地址alloc的历史,这样我们就可以用命令把这个地址还原出来。如图:(跟设置NSZombieEnabled一样,添加MallocStackLoggingNoCompact,并且设置为YES)



这样,当出现崩溃原因是message sent to deallocated instance 0x7179910,我们可以使用以下命令,把内存地址还原:

info malloc-history [b]0x7179910[/b]

如图,这个命令能具体把这个地址在哪一行代码生成还原出来。





(需要注意的是,因为这个命令只支持gdb,所以必须把控制台的输出改成gdb,并且有点遗憾的是,只支持模拟器,不支持真机调试)



(同样是通过Product->Scheme->Edit Scheme进入上面编辑页面,选中Info tab)

这样,好好检查一下那一行的代码,应该就很容易找出问题所在了。

如果不想用GDB,用以下办法



在XCode的以前版本中,如果遇到了

[代码]c#/cpp/oc代码:

1
message
sent to deallocated instance 0x6d564f0
我们可以使用info malloc-history 0x6d564f0来查看调用堆栈来查看崩溃发生的地方,这种方法这里不作阐述,大家自行百度。

 

在新的XCode里,调试器默认使用LLDB,我就讲一下如何在LLDB状态下定位到由于内存操作不当引起的Crash

首先我有一段会发生崩溃的代码:

[代码]c#/cpp/oc代码:

1
NSString
*themePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:themePathTmp];
2
if
(themePath)
3
  
self.backgroundIV.image
= [UIImage imageWithContentsOfFile:[themePath stringByAppendingPathComponent:
@"mask_1.png"
]];
4
  
 
5
[themePath
release];
学过内存管理的人都应该知道在这里themePath并没有被retain,所以如果写了release,那么必然会发生崩溃情况。首先我们需要对开发的环境变量进行设置



 

运行代码,出现下面的崩溃现象



 

下面我们打开“活动监视器”,找到我们对应的PID,我们的Target为HPThemeManager,只要找到HPThemeManager对应的PID就可以(HPThemeManager是在论坛里下载的,本来正在看代码,就直接拿他来作试验了)



 

现在,我们得到了两个主要的信息:

进程ID:50127

崩溃地址:0x6d564f0

我们打开终端,输入以下命令:

[代码]c#/cpp/oc代码:

1
sudo
malloc_history 50127 0x6d564f0
结果显示为:



 

这样我们用能定位到这行代码

[代码]c#/cpp/oc代码:

1
NSString
*themePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:themePathTmp];
对themePath进行排查,就找到了崩溃的罪魁祸首

[代码]c#/cpp/oc代码:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: