内存错误

1、内存错误是啥

在C和OC中,你一直在处理指针。指针是存储另一个变量的内存地址的变量。当向一个对象发送消息时,指向该对象的指针将会被引用。这意味着,你获取了指针所指的内存地址,并访问该存储区域的值。

当该存储器区域不再映射到你的应用时,或者换句话说,该内存区域在你认为使用的时候却没有使用,该内存区域是无法访问的。 这时内核会抛出一个异常( EXC ),表明你的应用程序不能访问该存储器区域(BAD ACCESS) 。

总之,当你碰到 EXC_BAD_ACCESS ,这意味着你试图发送消息到的内存块,但内存块无法执行该消息。但是,在某些情况下, EXC_BAD_ACCESS 是由被损坏的指针引起的。每当你的应用程序尝试引用损坏的指针,一个异常就会被内核抛出。

1
2
3
4
5
6
7
8
9
10
11
12
13
static NSMutableArray *array;

- (void)viewDidLoad
{
[super viewDidLoad];
array = [[NSMutableArray alloc] initWithCapacity:5];
[array release];
}

- (void) viewWillAppear:(BOOL)animated
{
[array addObject:@"Hello"];
}

上面的代码就会出现 EXC_BAD_ACCESS 错误,错误日志为:

1
-[CALayerArray addObject:]: unrecognized selector sent to instance 0x604000443480

其中 0x604000443480 就是 array 变量的地址。

ps: Xcode7.0 之后的版本在编译上面的代码时,会在“[array release];”处报错:

1
release is unavailable in automatic reference counting mode

所以,为了模拟上面的 EXC_BAD_ACCESS 错误,需要对编译环境进行设置:

1
Build Settings -> Objective-C Automatic Reference Counting -> NO。

2、咋调试?(Zombie 模式)

EXC_BAD_ACCESS 难以调试的原因是,你不知道你的应用程序试图访问哪个对象时出了问题。在 Xcode 中,启用僵尸对象意味着被释放的对象将会以僵尸的形式被保留。如果向僵尸对象发送消息,应用程序将会由于 EXC_BAD_ACCESS 而崩溃,此时 Xcode 就可以告诉你你试图访问的是哪个僵尸对象。

下面是在 Xcode9.2 中开启僵尸调试模式的步骤:

1
左上角Edit Scheme -> Run -> Diagnostics -> 勾选Zombie Objects

设置完之后还是上面的代码,再次运行之后,会打印如下报错信息:

1
2
Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
*** -[__NSArrayM addObject:]: message sent to deallocated instance 0x60400045d1c0

找到问题后记得还原 scheme中的 Zombie 设置。


内存错误
https://davidlii.cn/2018/07/25/memory-error.html
作者
Davidli
发布于
2018年7月25日
许可协议