iOS内存管理的原理是引用计数,引用计数就是统计一块内存的所有权,当这一内存被创建或者被另一对象或指针指向时候,引用计数会+1; 之后不再持有内存的时候,引用计数-1;当一块内存的引用计数变为0,表示没有任何对象或指针持有这块内存,系统便会释放掉这块内存。
MRC ARC
Objective-C中提供了两种内存管理机制MRC(Mannul Reference Counting)和ARC(Automatic Reference Counting),分别对应内存的手动和自动管理。
- MRC 需要我们自己添加创建和释放的代码,自定义管理内存,谁分配谁释放的原则;
- ARC 本质其实是MRC,系统编译期在合适的地方帮我们添加了 retain 和 release等代码,减少了代码的同时降低了内存出错的概率;
MRC
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString* str = [[[NSString alloc] initWithString:@"test"] autorelease];
//use str...
[pool release];
//str is released
release autoRelease
release是一个实例方法,只能由对象调用,它的作用是使对象的内存空间的引用计数减1,若引用计数变为0则系统会立刻释放掉这块内存。
autorelease也是一个实例方法,同样只能由对象调用,它的作用于release类似,但不是立刻减1,相当于一个延迟的release,通常用于方法返回值的释放。
那么问题来了,autoRelease对象到底什么时候会被释放 ?
所有 autorelease 的对象,在出了作用域之后,会被自动添加到最近创建的自动释放池中;在一次完整的运行循环结束之前,会被销毁;
关系如此:(线程-RunLoop-AutoRelease Pool-AutoRelease)
autorelease对象是在当前的runloop迭代结束时释放的,而它能够释放的原因是系统在每个runloop迭代中都加入了自动释放池Push和Pop;
autoReleasePool 没有单独的结构,autoReleasePoolPage双向链表; 向一个对象发送 - autorelease消息,就是将这个对象加入到当前AutoreleasePoolPage的栈顶next指针指向的位置。
void *context = objc_autoreleasePoolPush();
// {}中的代码
objc_autoreleasePoolPop(context);
AutoRelease Pool
我们知道系统自动释放池会在runloop 迭代结束时释放autorelease 对象,然而为了能够改变其释放时机;pool本质上是一个stack,扔到pool中的对象等价于入栈。我们把需要及时释放掉的代码块放入我们生成的autorelease pool中,结束后清空这个自定义的pool,主动地让pool清空掉来达到及时释放内存的目的。
AutoreleasePool 可以在某些情况下,大幅度降低程序的内存占用(自定义NSOperation内存泄露问题;循环处理中,循环体里面的对象都是临时创建使用的情况etc);
关键字
上次在Property中说,它是ivta+存取方法;
而这些内存管理关键字(strong,weak,assign,retain,copy,mutablecopy)系统是如何来帮我们处理的 留坑
在ARC的项目中,对MRC的文件可以添加编译选项-fno-objc-arc的标识来解决编译问题;
网友评论