这是我参与「第四届青训营-iOS客户端」笔记创作活动的的第六天。本篇文章主要讲解iOS的内存管理如ARC、MRC、自动释放池等。
一、NSObject--分配内存空间&初始化
alloc和init这两个方法在我们创建任何对象时都会用到。类型名称+alloc就会得到一个空的实例,为新对象分配内存空间;类型名称+init就是对空的实例进行初始化。new的用法跟alloc+init一样,New=alloc+init也就是说[[NSObject alloc]init]等于[NSObject new ]。
二、iOS内存管理
任何继承了NSObject的对象都需要进行内存管理。
1.引用计数 Reference Counting
引用计数是编程语言中的一种内存管理技术,它可以记录当前内存资源(如对象、内存等等)有多少个指针在引用。在OC语言中,引用计数可以用来进行内存管理。每增加一次资源引用,引用计数就会加一也就是递增;每减少一次资源引用,引用计数就会减一也就是递减。当引用计数等于0的时候,对象就会被销毁。
2.MRC--Manual Reference Counting
由alloc、new、copy、mutableCopy开头的方法创建的对象引用计数=1。
我们知道[[NSObject alloc]init]等于[NSObject new ]。如果对一个对象发送retain消息,可以让引用计数递增(+1);如果对一个对象发送release消息,可以让引用计数递减(-1)。当对象的引用计数为 0 时,即将销毁的时候,系统会向对象发送一条dealloc消息 (不能直接调用 dealloc)。
引用:juejin.cn/post/684490…
内存管理原则:
如果通过alloc、new、copy或mutableCopy来创建一个对象,那么必须调用release或者autorelease。如果调用了retain就一定要调用一次release。
retain:
在没有使用alloc、new、copy、mutableCopy来产生对象的情况下,NSMutableArray通过类方法array产生了对象但并没有使用,这个对象是不属于object自身产生的。为了让object可以持有该对象(尽管该对象不是他产生的)就需要使用retain方法让对象计数器+1。
release:
它会使对象的内存空间的引用计数减1,若引用计数变为0则系统会立刻释放掉这块内存。如果引用计数为0的基础上再调用release,便会造成过度释放,使内存崩溃。
assign:
默认属性就是assign,它只会生成getter/setter方法
copy:
系统会自动生成getter/setter方法内存管理的代码。
3. ARC--Automatic Reference Counting
与MRC不同:
- 不用考虑retain/release。
- 只要有一个强指针在内存指向对象,对象就不能释放。ARC销毁时机的前提是强引用的个数为0,而不是引用计数为0。
- 默认所有对象变量的指针都是强指针,如果是弱指针的话需要声明。
- 不允许调用
release、retain、autorelease方法。
strong : 用于OC对象,相当于MRC中的retain,是强引用。
weak : 用于OC对象,相当于MRC中的assign。
assign : 用于基本数据类型,跟MRC中的assign一样,也可修饰对象,但会存在野指针(野指针:一个已删除的对象或者受限内存区域的指针,比如说就是这个指针指向的内存,在别处被回收了,但是这个指针不知道,依然还指向这块内存。)
copy : 主要用于修饰block、字符串、数组。
4.自动释放池--Autorelease-Pool
对象会放到自动释放池,统一释放。自动释放池不会立刻就释放对象而是会延迟对象的释放直到自动释放池被清理。
三、循环引用
循环引指的是两个或多个对象通过相互之间的强引用,形成了一个保留环,即使已经没有外部对象持有,也无法对其进行释放操作,也无法释放其占用的内存空间并且引用计数器始终大于0。由于循环引用的存在,使得产生循环引用的对象始终占有内存空间,导致在程序结束后始终销毁不了,所以循环引用是不被允许的。
Delegate 代理模式
@protocol协议:定义了方法,任何对象都可以继承协议实现方法。这个方法可以有各种各种的实现。
循环引用解决办法:
1.Delegate所导致的互相引用:用weak代替strong。
2.由block导致的循环引用:将其中一个变为弱引用(ex.__weak typeof(self) weakSelf = self;)。
四、思考
copy和mutableCopy有什么区别?
copy是不可变拷贝,也就是说哪怕用copy拷贝的对象原本是可变的,但是拷贝后也不可变。mutableCopy是可变拷贝,也就是说哪怕用mutableCopy拷贝的对象原本是不可变的,但是拷贝以后也是可变的。
深拷贝与浅拷贝有什么区别(Shallow Copy vs. Deep Copy)?
浅拷贝:指的是指针拷贝,拷贝了一个新的指针,指向同一个内存区域,没有拷贝内存。并没有产生新对象,引用计数加一。
深拷贝:指的是内容拷贝,拷贝数据到一块新的内存区域。产生了新对象,所以引用计数等于1。(深拷贝一般都是在不可变转换成可变的时候使用)
weak与assign的区别?
- weak只能修饰对象;assign可以修饰对象和基础数据类型。
- weak线程安全,不会产生野指针问题;assign如果只修饰基础数据类型是安全的,但是如果修饰对象的话就有可能产生野指针问题。
autorelease和release有什么区别?
release会立刻释放对对象的强引用,而autorelease会延迟对象的释放直到自动释放池被清理。
Reference
《内存管理系列—OC的内存管理模式》juejin.cn/post/684490…
《iOS野指针定位总结》juejin.cn/post/684490…
《OC底层探索19-weak和assign区别浅谈OC底层探索19-weak和assign区别浅谈》cloud.tencent.com/developer/a…
《Objective-C 内存管理》juejin.cn/post/712344…
《【OC梳理】循环引用及解决》www.jianshu.com/p/b7b6d345b…