前言

iOS中由于有ARC的存在,经常有博客会讲到循环时的内存堆积问题,主动参加autoreleasepool能够避免内存延时开释,降低内存峰值,这也是面试中优化方面常会被考察的点,所以项目中基本上凡是有有较多数据循环的当地都会被手动参加autoreleasepool,如果你没加,在code review的时分都会被以为为“没有必定内存方面的思考”(菜鸡)

本文不会去讲autoreleasepool的原理数据结构等常识(许多优异的博客都讲的很好了),只会针对autoreleasepool用法这一点进行探讨

那么问题来了,你加的autoreleasepool真的有用么??

下面截取一段某大厂对外供给的demo代码片段(已做简化)

你真得懂autoreleasepool的用法么

刚好由于需求看到了这段代码实在是太典型了,也是本身项目中众多循环代码的缩影,所以促成了想写这篇帖子的想法

槽点:创立的item会被加到数组中,本身就不会开释,为什么要加autoreleasepool

那去掉add操作后代码如下

你真得懂autoreleasepool的用法么

看起来就比较像许多示例代码了,实际测验下来也并没有发生内存堆积导致的峰值升高

那把autoreleasepool去掉呢?代码如下

你真得懂autoreleasepool的用法么

测验下发现也没有发生内存堆积导致的峰值升高

原因:许多人错误的了解了ARC导致以为创立的目标实际都是归autoreleasepool去办理的

实际上直接经过alloc 、new等创立的目标都是靠ARC主动刺进release开释的,跟autoreleasepool没啥联系,只要被autorelease的目标才会被参加到主动开释池中受autoreleasepool的办理,代码如下

你真得懂autoreleasepool的用法么

验证下确实会由于autorelease的开释机制(RunLoop)导致因内存堆积导致的峰值升高,此刻手动参加autoreleasepool进行办理,就不会有内存堆积导致的峰值升高的问题了,代码如下

你真得懂autoreleasepool的用法么

总结如下

你真得懂autoreleasepool的用法么

但是实际开发中绝大多数目标都是直接经过alloc 、new等创立出来的,目标都是靠ARC主动刺进release开释的,手动autoreleasepool+__autoreleasing就显得有点多此一举了

那么问题又来了,__autoreleasing究竟应该啥时分用??

目前大厂面试都有必定的数据结构与算法方面的查核,现在来看下这一段代码,结构一条5W数据的链表

你真得懂autoreleasepool的用法么

你真得懂autoreleasepool的用法么

代码很简单看起来也没什么问题

运行一下会发现最终crash了

你真得懂autoreleasepool的用法么

原因:头结点析构后会开释本身持有的属性(cxx_destruct,这儿不去讲dealloc的流程 网上有许多优异的帖子)导致next指向的node析构…不断的析构导致stack overflow引发的EXC_BAD_ACCESS

我猜这可能也是根据引用计数机制的iOS没有供给链表(NSNode)这种数据结构的一个原因,经过链表完成的栈、行列也没有直接供给(NSMutableArray底层的环型数组机制也能保障头尾操作是O(1)的,能够作为栈、行列的平替)

那么如何处理呢??

能够在node目标的dealloc办法中手动制空next指针next指向的node目标析构,其原理是将开释节点提早了,不会导致stack overflow(详细参考dealloc流程),但也只是治标不治本,将数组量级增大仍是会导致stack overflow

你真得懂autoreleasepool的用法么

最终处理方案是将next参加到主动开释池中,由主动开释池办理其开释,就不是造成因链式析构导致的stack overflow问题了(详细参考autoreleasepool开释流程)

你真得懂autoreleasepool的用法么

RAC代码库里有更精密的完成(超越某一阈值后参加到autoreleasepool中),代码如下

你真得懂autoreleasepool的用法么

感触

1.期望这篇文章能对你有所协助,能更精准的运用autoreleasepool并对ARCautorelease等机制有更深化的了解

2.从业多年一向有想写点技术博客的激动,但受限于没想到写什么(iOS相关的帖子实在是太多了,基本你想写什么都有很优异的帖子存在了)和繁忙的工作(懒),这次因疫情原因总算鼓起勇气尝试了一下,期望能为以后打好根底

愿疫情早日完毕、世界和平

update

为SDWebImage提了pr#3388,已被兼并