美文网首页
第35条:用”僵尸对象“调试内存管理问题

第35条:用”僵尸对象“调试内存管理问题

作者: MrSYLong | 来源:发表于2018-10-14 16:12 被阅读3次

    向已回收的对象发送消息是不安全的。这么做是否可行完全取决于对象所占内存有没有为其他内容所覆写。

    Cocoa提供了僵尸对象这个方便的功能。启用这项调试功能后,运行期系统会把所有已经回收的实例转化为特殊的僵尸对象,而不会真正回收它们。

    僵尸对象收到消息后,会抛出异常,其中准确指出僵尸对象所收到的选择器及其原来所属的类,其中还包含接受消息的僵尸对象所对应的”指针值“。

    僵尸对象是调试内存管理的最佳方式。

    在Xcode中打启用僵尸对象:点击下图中左上角标注的位置选择 Edit Scheme,再选择run中的Diagnostics分页,勾选Enabled Zombine Objects选项。

    僵尸对象工作原理:它的实现代码深植于Objective-C的运行期库、Foundation框架及CoreFoundation框架中。系统在即将将回收对象时,如果通过环境变量启动了僵尸对象功能,那么将执行一个附加步骤,把对象转化为僵尸对象,而不彻底回收。

    下面代码就演示普通对象转换为僵尸对象的过程

    注意:采用的是手动计数,在Build Settings中将Objective-C Automatic Reference Counting设为NO即可不用ARC。

    #import <Foundation/Foundation.h>
    #import <objc/runtime.h>
    
    @interface EOCClass : NSObject
    @end
    
    @implementation EOCClass
    @end
    
    void PrintClassInfo(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, const char * argv[]) {
        EOCClass *obj = [[EOCClass alloc] init];
        NSLog(@"Before release:");
        PrintClassInfo(obj);
    
        [obj release];
        NSLog(@"After release");
        PrintClassInfo(obj);
        return 0;
    }
    
    运行结果:
    Before release:
    === EOCClass : NSObject ===
    After release
    === _NSZombie_EOCClass : nil ===
    

    对象所属的类已经由EOCClass变为NSZombie_EOCClass。这个类是代码中没有定义的,在运行期生成的。编译器首次遇到EOCClass类对象要变成僵尸对象时,就会在类名前加上_NSZombie前缀生成对应的僵尸类。

    僵尸类只是充当一个标记,它的作用会在消息转发过程中体现出来。当执行到完整转发时,“forwarding”函数会检查对象所属的类名,若名称前缀为NSZombie,表明消息接收者是僵尸对象,需要特殊处理,此时会打印一条消息,其中指明僵尸对象收到的消息及原来所属的类(僵尸类去掉前缀),然后应用程序终止。

    在之前代码末尾加上一句代码向僵尸对象发送消息:

    int main(int argc, const char * argv[]) {
        EOCClass *obj = [[EOCClass alloc] init];
        NSLog(@"Before release:");
        PrintClassInfo(obj);
    
        [obj release];
        NSLog(@"After release");
        PrintClassInfo(obj);
    
        // 向僵尸对象发送消息
        [obj description];
        return 0;
    }
    
    运行结果:
    Before release:
    === EOCClass : NSObject ===
    After release
    === _NSZombie_EOCClass : nil ===
    *** -[EOCClass description]: message sent to deallocated instance 0x1006002e0
    

    可以看到僵尸对象原来所属的类,收到的选择器以及对应的指针值都打印出来了。

    相关文章

      网友评论

          本文标题:第35条:用”僵尸对象“调试内存管理问题

          本文链接:https://www.haomeiwen.com/subject/dcttzftx.html