现在的位置: 首页 > 综合 > 正文

NSZombieEnabled惹的祸

2014年08月29日 ⁄ 综合 ⁄ 共 1157字 ⁄ 字号 评论关闭

今天在开发的时候遇到了一个奇怪的bug, 我创建了一个线程,然后线程里不断的生成autoRelease变量,如下面的代码:

- (void)run
{
    while (YES) 
    {
        @autoreleasepool {
            NSDate *showDate = [NSDate date];
        }
    }
}

结果运行的时候内存飞涨, 不一会儿就死了,开始我怀疑是autoreleasepool的问题,于是用了以前的NSAutoreleasePool,结果还是不行。然后我新建了一个工程来专门测试这个简单的线程,运行上面的代码,发现不会出现内存问题。后来我在有问题的工程中将线程代码中加入一个sleep(1);  结果autoreleasepool就正常工程了,内存也不涨了。

- (void)run
{
    while (YES) 
    {
        @autoreleasepool {
            NSDate *showDate = [NSDate date];
            sleep(1);
        }
    }
}

问题虽然解觉了,但是这样程运行效率不高,而sleep是以秒为单位的,追求完美的我,杂可能用这种解决方法呢。 用sleep还不如用

[NSThread sleepForTimeInterval:0.1];

这样效率更好,可是我还是不喜欢用这个睡觉的方法, 杂能睡觉呢,要一直抗起,最大限度利用cpu哟。

问题来了,为何加了睡觉的方法就可以了呢?为何autoreasepool 在新建的测试项目工程中没问题呢? 实在不知道原因,开始抓脑袋了。难道是我人品问题, 我杂能怀疑自己,怀疑apple了。 本人的人品一向都很好呀,杂可能遇到这样的问题呀。  就不信这个邪了,我认真想了一下,到底两个工程有何区别。最后突然想到了出问题的工程中设置了NSZombieEnabled,设置它有什么用? 是为了方便定位向已释放的instance发送消息crash位置。 我试着在出问题的工程中取消NSZombieEnabled,再运行程序,一切都是那么美好,内存恢复正常了,大哭,泪流满面呀。

分析其原因,由于设置了NSZombieEnabled,那么系统将instance释放的class标记为_NSZombie,此时内存并没有真正释放。因为如果后来发送消息到已释放的instance的时候,系统才知道这个instance其实是已经释放了,才能较为准确的定位crash位置。所以我遇到了本文开始外所说的问题:内存会一直上涨。至于为何要线程小睡一会儿就可以正常,到现在我也没有想明白。

如果大侠知道我不明白的地方的答案,还望给于指点一二。

reference:

http://www.cocoadev.com/index.pl?NSZombieEnabled

http://lists.apple.com/archives/cocoa-dev/2001/Oct/msg00231.html

抱歉!评论已关闭.