内存管理
iOS 是怎么管理内存的?
移动端的内存管理技术,主要有 GC(Garbage Collection,垃圾回收)的标记清除算法和苹果公司使用的引用计数方法。
相比较于 GC 标记清除算法,引用计数法可以及时地回收引用计数为 0 的对象,减少查找次数。但是,引用计数会带来循环引用的问题,比如当外部的变量强引用 Block 时,Block 也会强引用外部的变量,就会出现循环引用。
虚拟内存
1、由于要解决多程序多任务同时运行的这些问题,所以增加了一个中间层来间接访问物理内存,这个中间层就是虚拟内存。虚拟内存通过映射,可以将虚拟地址转化成物理地址。
2、分段就是将进程里连在一起的代码段、数据段、栈、堆分开成独立的段,每个段内空间是连续的,段之间不连续。
3、App 在运行时,大多数的时间只会使用很小部分的内存,所以我们可以使用比段粒度更小的空间管理技术,也就是分页。对于操作系统管理来说也会简单很多,只需要维护一份页表(Page Table)来记录虚拟页(Virtual Page)和物理页(Physical Page)的关系即可。
iOS常见的内存问题总结:
1、UIWebView内存消耗很大,是内存问题的重灾区,优化方案是使用WKWebView替换
2、大界面的渲染:view的Size过大或者View的层级过于复杂,优化方案是降低界面的复杂度
3、Autorelease对象:由于autorelease对象积累过多导致峰值内存增大爆内存,常见于循环创建对象、GCD串行队列中
4、大图片的解码:图片的Size过大导致内存占用过大,优化方法就是适当降低图片的清晰度和限制大图的缓存数量
5、内存泄漏:OC对象、malloc内存块泄漏或者C++对象泄漏经过一段时间的累积会导致爆内存
线程的优先级:
iOS 系统内核里有一个数组,专门用于维护线程的优先级。这个优先级规定就是:内核用线程的优先级是最高的,操作系统的优先级其次,App 的优先级排在最后。并且,前台 App 程序的优先级是高于后台运行 App 的;线程使用优先级时,CPU 占用多的线程的优先级会被降低。
hook大内存分配的函数:
1、iOS 系统在因为内存占用原因强杀掉 App 前,至少有 6 秒钟的时间可以用来做优先级判断。同时,JetSamEvent 日志也是在这 6 秒内生成的。didReceiveMemoryWarning 这个内存压力代理事件来动态地获取内存限制值。
2、内存分配函数 malloc 和 calloc 等默认使用的是 nano_zone。nano_zone 是 256B 以下小内存的分配,大于 256B 的时候会使用 scalable_zone 来分配。
3、其他使用 scalable_zone 分配内存的函数的方法也类似,所有大内存的分配,不管外部函数是怎么包装的,最终都会调用 malloc_logger 函数。这样的话,问题就好解决了,你可以使用 fishhook 去 Hook 这个函数,加上自己的统计记录就能够通盘掌握内存的分配情况。出现问题时,将内存分配记录的日志捞上来,你就能够跟踪到导致内存不合理增大的原因了。