美文网首页
第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