iOS野指针定位总结

野指针就是指向一个已删除的对象或者受限内存区域的指针。
我们写C++的时候强调指针初始化为NULL,强调用完后也为其赋值为NULL,谁分配的谁回收,来避免野指针的问题。
比较常见的就是这个指针指向的内存,在别处被回收了,但是这个指针不知道,依然还指向这块内存。
MRC 时代因为引用计数手动控制,所以内存很容易在别处被回收。ARC解决了大部分这种问题。、
在iOS9之前,系统库的delegatetarget-action有一部分是assign(unsafe_unretain)的形式,这时候如果内存在别处被回收了,也是会出现野指针的。
所以iOS9之后这些地方就改成了weak内存修饰符,内存被回收的时候通过weak表,把这些指针设为nil。也大幅度减少了野指针的出现。

如果现在在工程中依然频繁出现野指针,几乎可以肯定是错误地使用了内存。

表现:Crash

对于MachUnixNSException三种不同层级的crash,NSException比较好说,可以直接定位到OC代码。问题主要来自EXC_BAD_ACCESS(SIGSEGV)这种异常,难以在我们的应用代码中定位。

image

  • SIGILL 执行了非法指令,一般是可执行文件出现了错误
  • SIGTRAP 断点指令或者其他trap指令产生
  • SIGABRT 调用abort产生
  • SIGBUS 非法地址。比如错误的内存类型访问、内存地址对齐等
  • SIGSEGV 非法地址。访问未分配内存、写入没有写权限的内存等
  • SIGFPE 致命的算术运算。比如数值溢出、NaN数值等

实际我们遇到Mach Exception绝大部分都是野指针的问题。SIGSEGV/SIGABRT/SIGTRAP 比较多见。
野指针问题表现千奇百怪,而且因为崩溃的地方并不是造成野指针的地方,而且难以重现,所以问题往往难以定位。

image


腾讯Bugly的这张图可以看到,野指针几乎可以造成各种类型的Mach Exception

 

定位工具

Zoombie Object

这是目前帮助最大的调试模式。实现原理就是 hook 住了对象的dealloc方法,通过调用自己的__dealloc_zombie方法来把对象进行僵尸化。

id object_dispose(id obj)
{
    if (!obj) return nil;

    objc_destructInstance(obj);    
    free(obj);

    return nil;
}

正常的对象释放方法如上,但是僵尸对象调用了objc_destructInstance后就直接return了,不再free(obj);。同时生成一个"_NSZombie_" + clsName类名,调用objc_setClass(self, zombieCls);修改对象的 isa 指针,令其指向特殊的僵尸类。
如果这个对象再次收到消息,objc_msgsend的时候,调用abort()崩溃并打印出调用的方法。

野指针指向的内存没有被覆盖的时候,或者被覆盖成可以访问的内存的时候,不一定会出现崩溃。这个时候向对象发送消息,不一定会崩溃(可能刚好有这个方法),或者向已经释放的对象发送消息。 但是如果野指针指向的是僵尸对象,那就一定会崩溃了,会崩溃在僵尸对象第一次被其它消息访问的时候。

Zombie Object without Xcode

僵尸对象必须在连接Xcode中debug的时候使用,如果我们想跟我们的崩溃收集工具集成在一起,就需要自己实现类似Zombie Object的东西。
逻辑是通过hook住NSObject的根类的dealloc方法,然后在新的dealloc方法中将本来即将释放的对象的isa指针改为指向我们创建的一个新的僵尸类。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值