草庐IT

ARC下AutoReleasePool的误区

Yasin的简书 2023-03-28 原文

写这边文章的原因是看到网络上对于AutoReleasePool讨论,发现大家对AutoReleasePool存在误区。

AutoReleasePool 里面的对象何时释放?

这个问题是常见的iOS面试题,错误的答案:
1.等到一次runloop结束,AutoReleasePool被释放时
2.超出作用域{}

这些答案都不对,标准答案:
每次release时retainCount减一,当retainCount为0时候释放对象。release的时机比如runloop周期中AutoReleasePool被释放时,比如超出作用域时

关键概念点:
1. 不是所有OC对象都会加入到AutoReleasePool
2. AutoReleasePool被释放时里面的对象不一定会释放,超出作用域一样不一定会释放

  1. 不是所有OC对象都会加入到AutoReleasePool
    AutoReleasePool是ARC的一部分,本质上还是RC的机制,一个对象在ARC下,可能会被加入到autoreleasepool里面,也可能不会。比如被__autoreleasing标记或者@autoreleasepool包裹的或者UIImage对象都会加入AutoReleasePool,其他的像只是单纯创建NSObject是不会,但是调用了NSObject的对象方法后是会加入AutoReleasePool的。
  1. AutoReleasePool被释放时里面的对象不一定会释放,超出作用域同样的道理
    AutoReleasePool被释放时里面的对象可能还有其他引用,所以AutoReleasePool被释放时里面的对象只会执行release操作,并不一定会释放对象。
正常情况:
    __weak id objA = nil;
    {
        id objB = [NSObject new];
        objA = objB;
    }
    NSLog(@"%@", objA);
    // objA = null

这个是没有异议的情况,objB出了作用域就会被释放,但是下面的代码就不一样了

AutoReleasePool被释放时有其他引用:
    id objA = nil;
    @autoreleasepool {
        id objB = [NSObject new];
        objA = objB;
    }
    NSLog(@"%@", objA);
    // objA = <NSObject: 0x600002708330>

objB虽然被加入到自动释放池,但是并不会被释放掉,因为还有objA在强引用它。如果这里的objA是weak的,objB会被释放

出了作用域但是AutoReleasePool没有释放:
    __weak id objA = nil;
    {
        __autoreleasing id objB = [NSObject new];
        objA = objB;
    }
    NSLog(@"%@", objA);
    // objA = <NSObject: 0x600000c545c0>

objA虽然是弱引用,但是__autoreleasing的AutoReleasePool是和objA同级的,要等AutoReleasePool释放的时候objB才会被释放,即使objB已经出了作用域,其实这里出作用域的时候并没有执行release操作

AutoReleasePool释放了,同时出了作用域,就会被释放:
    __weak id objA = nil;
    {
        id objB = nil;
        @autoreleasepool {
            __autoreleasing NSObject *objC = [NSObject new];
            objB = objC;
        }
        objA = objB;
        NSLog(@"objA = %@", objA);
        //objA = <NSObject: 0x60000188c0c0>
    }
    NSLog(@"objA = %@", objA);
    //objA = null

源码分析

autoreleasepool pop源码:


image.png

release中的源码:


image.png

总结:

  1. 并不是所有对象都会被自动加入到AutoReleasePool
  2. runloop周期结束的时候AutoReleasePool会被释放
  3. AutoReleasePool被释放时里面的对象会执行release操作,但是并不一定会释放
  4. AutoReleasePool里面的对象要等到retainCount为0时候释放
  5. AutoReleasePool里面的对象出作用域的时候并不会立即执行release操作
  6. for循环中的对象如果造成了内存暴增,可以用@autoreleasepool 加入到临时自动释放池

有关ARC下AutoReleasePool的误区的更多相关文章

  1. javascript - 非常简单的 D3 : How to Draw an Arc? - 2

    学习D3会很好。看了很多例子,我想我明白了。我的第一个项目是制作一个色轮,为了简单起见没有过渡。但对于我的第一个项目来说,这似乎还不够简单!对于零号项目,我试图在屏幕上显示一些内容。希望我写的东西(并且亲爱的阅读已经修复),而不是一个例子。我做错了什么?http://jsfiddle.net/aGdMX/1/vararc=d3.svg.arc().innerRadius(40).outerRadius(100).startAngle(0).endAngle(1);varchart=d3.select("body").append("svg:svg").attr("class","cha

  2. javascript - 在 d3 arc javascript 中绘制文本 - 2

    我在http://jsfiddle.net/PRb93/1/上用d3创建了一个弧varvis=d3.select("body").append("svg")varpi=Math.PI;vararc=d3.svg.arc().innerRadius(300).outerRadius(320).startAngle(0*(pi/180)).endAngle(-pi)vis.append("path").attr("d",arc).attr("transform","translate(350,350)")​现在我想在这个圆弧的顶部绘制文本(我将把这个圆弧分布到n个节点中)。我不能直接使用和

  3. javascript - D3 : gauge chart with growing arc - 2

    我想实现类似表示5个级别的不断增长的弧线(见图)。我的数据只有一个介于1-5之间的整数值。您现在可以忽略中间的图标。有没有可能在d3中实现类似的东西?我找不到任何例子。此外,我尝试使用切掉的饼图(donut)图表方法进行尝试,但我无法做出不断增长的弧线......我将不胜感激任何帮助!谢谢。 最佳答案 您可以使用d3执行此操作,而无需依赖外部图像、SVGSprite或DOM中的任何内容—只需d3.js。这是一个workingfiddle.下面解释实现。而且,这里有一个moreadvanced在不断增长的弧线上动画剪辑路径的fiddl

  4. javascript - 未捕获的类型错误 : Cannot read property 'arc' of undefined in AngularJS and D3 - 2

    我是AngularJS和D3的新手。我正在使用这些技术构建仪表板。我已将d3.min.js文件包含在索引文件中并尝试用它绘制一个圆圈。代码如下:entercodeherevarsvg=d3.select("body").append("svg").attr("width",200).attr("height",200).append("g").attr("transform","translate(100,100)");vararc=d3.svg.arc().innerRadius(50).outerRadius(70).startAngle(0).endAngle(2*Math.PI

  5. php - 是否可以在 ARC2 中对已解析的三元组进行 SPARQL 查询? - 2

    ARC2文档不是很准确。它给出了以下两个示例:首先,解析一个RDF文件:$parser=ARC2::getRDFParser();$parser->parse('http://example.com/foaf.ttl');$triples=$parser->getTriples();其次,在数据存储上进行SPARQL查询:$q='SELECT...';$rows=$store->query($q,'rows');...但是是否可以直接对解析后的$triples进行SPARQL查询? 最佳答案 恐怕ARC2没有内存中的SPARQL处理

  6. php - 导出和导入 ARC2 RDF 数据的最佳方式是什么? - 2

    最初,我这样做是错误的:我使用MySQL来复制表。这很糟糕,因为ARC2对其表列之一使用了平台相关的哈希函数。所以,我认为解决方案很简单://Toexport$store->createBackup('backup_file.spog');//Toimport$store->query('LOAD');我想发布这个问题,以防有人有更多建议。我对RDF和ARC2还是个新手。有关ARC2问题的更多信息:为了在MySQL数据库中查找主题URI,ARC2使用http://php.net/crc32哈希函数。结果整数不是32位。尽管crc32()使用“一次32位长度的输入字符串”准备校验和,但生

  7. ES中 minimum_should_match 的用法和误区 - 2

    背景写这篇文章是因为有个同学在群里发了这么一张截图,图中讲的两点关于``的描述,我看了一眼,两个都是错的。目前互联网上的文章质量参差不齐,这也算是为了提高网络博客的质量进一己之力吧。上述截图中的两个认知误区1、不能简单的说7.0版本之后默认值是0或者1minimum_should_match是ES组合查询中的一个常用参数,参数指定should子句返回的文档必须匹配的子句的数量或百分比。注意这里可以输具体的数量,也可以是百分数指定。并且满足以下两个条件:如果bool查询包含至少一个should子句,而没有must或filter子句,则默认值为1。即此时minimum_should_match如果

  8. c++ - 如何使用 ARC 使 C++ 模板适用于 Objective C 类型? - 2

    举个简单的例子。如果我在没有ARC的情况下编译以下main.mm文件,它可以正常工作。#importtemplateinttesting(constT&whoCares){return0;}intmain(intargc,constchar*argv[]){returntesting(@"hello");}如果我用ARC编译它,会出现以下错误:/Users/sam/Projects/TemplateTest/TemplateTest/main.mm:10:12:error:nomatchingfunctionforcallto'testing'returntesting(@"hello

  9. c++ - 在启用 ARC 的情况下使用 reinterpret_cast - 2

    我在支持ARC的Objective-C项目中包含了一个库的头文件。我知道库没有在启用ARC的情况下编译,但问题出在库的头文件上,特别是这些行:templatestaticinlineType_&MSHookIvar(idself,constchar*name){Ivarivar(class_getInstanceVariable(object_getClass(self),name));void*pointer(ivar==NULL?NULL:reinterpret_cast(self)+ivar_getOffset(ivar));return*reinterpret_cast(poi

  10. c++ - 编译器优化还是我的误区 - 2

    最近我在测试一些C++的深暗角落,我对一个微妙的地方感到困惑。我的测试其实很简单://problem1//noanyconstructorcall,g++actsasafunctiondeclarationtothe(howmany())//g++turns(howmany())into(howmany(*)())howmanyt(howmany());//problem2//onlyoneconstructorcallhowmanyt=howmany();我对上面的期望是;第一个howmany()构造函数调用将生成一个临时对象,然后编译器将使用该临时对象和复制构造函数来实例化t。然而

随机推荐