今天给大家分享下IOS的内存管理相关的知识。这个也是外面大厂面试必问的一个问题。掌握这个知识点,对面试和开发都十分必要。
内存分区情况
首先我们需要知道一个事情:通过我们写好的代码会划分到那些区域呢?一般来说有以下几个区域:代码区,数据区,常量区,全局区,堆区,栈区。
-
代码区
存放函数体的二进制代码。就是我们写好的代码。
-
数据区
存放数据。
-
常量区
存放常量字符串。我们经常在.h文件定义一些常量, #define Name @“xxxx”。
一般在程序结束的时候,由系统释放。不知道你有没有印像,这类字符串我们从来没有释放过。
-
全局区
存放全局变量,静态变量。
一般在.m文件的函数体外定义 int gXXX之类的就是全局变量;加上static 关键字的就是静态变量;
其中初始化的全局变量,静态变量在全局的一个区域;未初始化的全局变量,静态变量在全局的另一个区域。同样地,也是在程序结束的时候,由系统释放。
-
堆区(Heap)
由程序员创建的变量分配的区域,是不连续的一块区域。一般使用了new,alloc,calloc,malloc 关键字创建的变量。这些变量需要程序员调用delete,release关键字来手动释放,若没有调用,则会造成内存泄露。这些是要特别注意的。
-
栈区(Stack)
存放函数的参数,局部变量,
由编译器自动分配释放。
划重点:主要关注由程序员使用new,alloc,calloc,malloc 关键字创建的变量。
IOS内存管理机制
一句话:在iOS中,使用引用计数来管理OC对象的内存。
具体就是,当一个新对象被创建,它的引用计数默认是1,调用retain一次会让OC对象的引用计数+1,调用release一次会让OC对象的引用计数-1,当引用计数减为0,OC对象就会销毁,释放其占用的内存空间。
看一个经典的面试题。
NSMutableArray *array = [[NSMutableArray array] retain];
NSString *str = [NSString stringWithFormat:@"test"]; //1
[str retain]; //+1
[array addObject:str]; //+1
NSLog(@"%d",[str retainCount]); // =3
[str retain]; //+1
[str release]; //-1
[str release]; //-1
NSLog(@"%d",str,[str retainCount]); //=2
[array removeAllObjects]; //-1
NSLog(@"%d",[str retainCount]); //=1
内存管理原则
在IOS面试中还会问到内存管理的原则。
一般是“谁创建,谁释放”的原则。
循环引用
还有一类与内存相关的循环引用问题,也是面试时乐此不疲的。
只有在堆中的相互引用无法回收,有可能造成循环引用。简单来说就是调用了new,alloc等关键字才有可能出现循环引用。
循环引用的实质:多个对象相互之间有强引用,不能释放,导致无法回收。
解决方法:一般是将 strong 引用改为 weak 引用。
一般出现的场景有:
1.父类与子类:在使用UITableView 的时候,将 UITableView 给 Cell 使用,cell 中的 strong 引用会造成循环引用。
2.block:block在copy时都会对block内部用到的对象进行强引用的。
self.testObject.clickBlock = ^{
[self doSomething];//这个self就是强引用
};
3.Delegate:delegate 属性的声明一般是weak的。
@property (nonatomic, weak) id <TestDelegate> delegate;
至此,IOS的内存管理分享完了,谢谢。