写高质量OC代码52建议总结:35.用僵尸对象调试内存管理问题

向已回收的对象发送消息是不安全的。具体是否可行看具体情况,取决于对象所占用的内存是否被其他内容覆写。但这无法确认。在程序没有崩溃的情况下,那块内存可能只复用了其中一部分,对象中的某些二进制数据依然有效。还有一种可能,就是那块内存恰好被另外一个有效且存活的对象所占据。在这种情况下,运行期系统会把消息发送到新对象那里,如果新对象无法响应方法,程序依然会崩溃。


Cocoa提供了“僵尸对象”,启动这项功能,运行期系统会把已经回收的对象转化成僵尸对象,而不会真正回收。这种对象所在的核心内存无法重用,所以不可能覆写。僵尸对象收到消息后会抛出异常,并描述哪个对象出了问题。
 
僵尸对象的工作原理,把已回收的对象转化为僵尸对象,而不彻底回收。
 
#import <Foundation/Foundation.h>
 #import <objc/runtime.h>
 
 @interface EOCClass : NSObject
 @end
 
 @implementation EOCClass
 @end
 
 void PrintClass(id obj) {
    Class cls = object_getClass(obj);
    Class superCls = class_getSuperclass(cls);
    NSLog(@"=== %s : %s ===", class_getName(cls), class_getName(superCls));
 }
 
 int main(int argc, char *argv[]) {
    EOCClass *obj = [[EOCClass alloc] init];
    NSLog(@"Before release");
    PrintClassInfo(obj);
 
    [obj release];
    NSLog(@"After release");
    PrintClassInfo(obj);
 }

以上代码中的函数,并没有直接给对象发送Objective - c的class消息,而是直接调用运行期object_getClass()函数。因为如果参数已经是僵尸对象了,直接发送OC消息会导致程序崩溃。
 
对象所属的类已经从EOCClass变为_NSZombie_EOCClass。_NSZombie_EOCClass实际上是在运行期产生的,当首次碰到EOCClass类的对象要变成僵尸对像时,就会创建僵尸类。僵尸类是从名为_NSZombie的模板里复制出来的。这些僵尸只是充当一个标记。
 
 Class cls = object_getClass(self);
 const char *clsName = class_getName(cls);
 const char *zombieClsName = "_NSZombie_" + clsName;
 Class zombieCls = objc_lookUpClass(zombieClsName);
 
 if(!zombieCls){
    Class baseZombieCls = objc_lookUpClass("_NSZombie_");
    zombieCls = objc_duplicateClass(baseZombieCls, zombieClsName, 0);
 }
 objc_destructInstance(self);
 objc_setClass(self, zombieCls);


整个过程其实就是NSObject的dealloc方法。运行期系统如果发现NSZombieEnabled的环境变量已经设置,就把dealloc方法“调配”成可以执行上述代码的方法。

僵尸类和NSObjec一样也是一个根类,并未实现任何方法,只有一个实例变量isa,所以发给它的全部消息都要经过消息转发机制。

 
总结:
1.系统在回收对象的时候,可以不将其真的回收,而是把它转化为僵尸对象。通过环境变量NSZombieEnabled可开启此功能。
2.系统会修改对象的isa指针,另其指向特殊的僵尸类,从而使该对象变为僵尸对象。僵尸类能够相应所有的选择子。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值