iOS内存优化
无论面试还是工作希望这篇文章可以解决所有关于iOS内存优化的问题。
所有问题的解决方式都是有基本上的三个提问:是什么?为什么?怎么做?因此对于内存优化的点首先可以做出如下提问:为什么需要内存优化?内存消耗在什么地方?系统是否提供内存管理的方法?处理内存管理的最佳实践有哪些?以上问题在下面的文档中都会提现并作出解答。
为什么内存需要优化?
应用的内存使用量超过单个进程的上线,就会被操作系统终止。
内存的消耗体现在什地方?
内存消耗指的是应用消耗的RAM。应用中内存消耗分为两部分:栈大小、堆大小。每个进程的所有线程共享一个堆空间,每个线程都有专用的栈空间。
堆大小
系统分配给应用的堆大小不会超过512M,同时应用不能控制分配给它的堆,只有操作系统可以管理堆。通过类创建的对象相关的所有数据都存放在堆中。
消耗堆内存的操作:使用NSSting、载入图片、创建使用Json/XML数据等。(待补充)
优化点:图片缓存、数据缓存、降低接口数据大批量输出等。(待补充)
栈大小
栈大小跟线程有关,那么创建线程通常是用来做什么呢?
常见的创建线程有:异步请求、本地缓存sql数据等。更具栈大小的优化点可知不能无限先在创建的线程调用方法。
降低栈大小的操作:相爱时可被递归调用的最大方法树、一个方法最多可以使用的变量数、视图层级在可嵌入的最大深度。
内存的管理模型是什么?
或者说iOS是如何管理内存的?
内存管理模型基于持有关系的概念。如果一个对象正处于被持有关系状态,那它占用的内存就不会被回收。这种持有关系技术通常被称为引用计数。MRC:手动引用计数、ARC:自动引用计数。同时因为ARC的带来的新的引用特性:弱引用。
弱引用:不会增加引用计数,因此不会扩展对象的引用声明周期。
强引用:强引用是默认的引用类型,被强引用指向的内存不会释放,强引用会增加引用计数,同时会扩展对象的声明周期。
自动引用计数:
特点:不在使用retain、release和autorelease;ARC是编译器的一种特性,它会评估对象在代码中,并在编译时自动注入适合的内存管理调用。同时系统默认开始ARC。
变量限定符:
__strong、 _weak 、_unsafe_unretained、 _autoreleasing
Person * _strong p1 = [[Person allon]init];
//创建对象后引用计数为1,并且对象在p1引用期间不会被回收
Person * _weak p2= [[Person allon]init];
//创建对象后引用计数为0,对象会被立即释放,且p2将被置为nil
Person * _unsafe_unretained p3 = [[Person allon]init];
//创建对象后引用计数为0,对象会被立即释放,且p3不会被置为nil
Person * _autoreleasing p4= [[Person allon]init];
//创建对象后引用计数为1,当方法返回时对象会被立即释放
属性限定符:
strong 、weak 、assign 、copy 、retain 、unsafe_unretained
注意点:布尔类型使用assign限定符、retain是MRC时期的产物
循环引用:
当两个不同的对象各有一个强引用指向对方,就会造成循环引用
循环引用的常见场景:
委托、Blocks、线程与计时器、键值对
处理方式如下:
委托
@protocol TestDataDelegate <NSObject>
- (void)onDataModel;
@end
@interface TestClass
@property (nonatomic,weak) id<TestDataDelegate>delegate;
- (void)delegate;
@end
@implementation TestClass
- (void)cancel{
self.delegate = nil
}
@end
Blocks
SomeViewController *vc = [[SomeViewController alloc]init];
_weak typeof(weakSelf) = self;
[self presentViewController:vc animated:YES completion:^{
typeof(self) theSelf = weakSelf;
if (theSelf !=nil){
theSelf.data = vc.data;
[theSelf dismissViewControllerAnimated:YES completion:nil];
}
}];
线程与计时器
- (void)close{
[self.timer invalidate];
self.timer = nil;
}
观察者:
- (void)dealloc{
[self removeObserver];
}
内存分析工具:
使用Instruments选择Leaks进行检测。
内存管理的最佳实践?
- 避免大量的单例
- 对子对象使用 _strong
- 对父对象使用_weak
- 对是引用图闭合的对象如委托代理使用_weak
- 对数值属性NSInteger SEL CGFloat等使用assign
- 对块属性,使用copy
- 避免在块内直接引用外部的变量。在块外面将他们weakify,并在块内再讲他们strongify.
- 进行必要的清理:销毁定时器、移除观察者、解除回调
备注:关于iOS内存优化先关知识的整理,相关内容来时《高性能iOS开发》、网络资源。以上内容如果需要会在后续慢慢补充完善,知道彻底理解内存相关的知识点。