ARC在Release与Debug模式中内存释放的坑

以一个方法起头:

- (void)createCat {
    
    NSObject *cat = nil;
    if (!cat) {
        cat = [[NSObject alloc] init];
    
        //1
    }
    
    //2
}
复制代码

当调用 createObject 方法, object 对象会在什么时候释放? 我猜大部分人会回答在位置2释放. 从语法层面解释也比较容易, 局部变量在作用域内默认是 strong 的, 所以出了作用域局部变量才会释放.

而若是我们在位置2增加 log, 也很容易证实这一点, 的确在位置2的时候没有释放.

然而实际情况并没有这么简单, 从现象看来用薛定谔的猫比喻比较恰当: 当你在观察它, 它就是活的, 当你不观察他, 它已经死了.

当然我们的观察是"直接"打印它. 但什么时候代码变成玄学了? 看到这里你肯定认为博主在胡诌, 下面做个试验: 我们创建一个 weak 修饰的 property, 当创建一个 cat 后, 让这个 property 指向这个 cat. 我们通过 log 这个 weak property 间接"观察"它有没有死.

//_catWeakProperty 为 weak property
- (void)createCat {
    
    NSObject *cat = nil;
    if (!_catWeakProperty) {
        cat = [[NSObject alloc] init];
        _catWeakProperty = cat;
    }
    
    NSLog(@"cat: %@", _catWeakProperty);
    //NSLog(@"cat: %@", cat);
}
复制代码

运行起来, 没错, 打印出来的 cat 真的是 nil, 已经释放, 但你将下一行注释打开, 直接 log 这个对象, 它又并没有释放.

看到这里是不是觉得很没有道理, 其实是还是有道理的, 上面没有说清楚运行环境: 这些代码只有在 ARC ==Release== 环境中才会是这种效果, 如果在 Debug 环境中, 无论如何这个对象无论如何都不会释放. 如果在网上搜 Debug 和 Release 的相关不同, 会发现很多博客都有说 Debug 环境内存会延迟释放, 而 Release 环境内存达到释放时机会立即释放. 这样说也没毛病, 实际按苹果官方的说法这只是 ARC 环境中运行时的一些优化, 但具体优化策略苹果是不会告诉你的...

Is ARC slow?

It depends on what you’re measuring, but generally “no.” The compiler efficiently eliminates many extraneous retain/release calls and much effort has been invested in speeding up the Objective-C runtime in general. In particular, the common “return a retain/autoreleased object” pattern is much faster and does not actually put the object into the autorelease pool, when the caller of the method is ARC code.

-- Transitioning to ARC Release Notes

这种情况非常特殊, 必须是 weak property(__weak 不会优化), 局部变量的生成在其他的作用域, ARC/Release 环境才会有这样的优化, 这也算是苹果的又一个坑吧, 记录一下, 以后查问题可以留个心眼.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值