一、基本概括
1.什么是内存管理?
内存管理,是指软件运行时对计算机内存资源的分配和使用的技术。其最主要的目的是如何高效,快速的分配,并且在适当的时候释放和回收内存资源。
2.为什么我们需要内存管理?
因为手机内存大小有限,如果有内存分配但是不释放它,哪怕这块内存已经不用了。导致你的应用程序占用越来越多的内存,并导致整体性能下降,或者直接在真机上闪退。因此需要把不必要的内存空间给释放掉。
3.内存管理分为:
手动内存管理(MRC Manual Reference Counting,手动引用计数,我们手动管理内存)。和自动内存管理(ARC Automatic Reference Counting,自动引用计数,由xcode,帮我们去管理内存)
在C语言中的内存管理,我们手动申请,手动释放。这样来看,我们只需要注意三个问题就好了:
1、申请内存,使用完成后需要释放,如果不释放会造成内存泄露。
2、不能多次释放,如果多次释放,则会崩溃。
3、不能提前释放,如果提前释放,数据不安全
C语言的内存管理方法:
缺点:
在一个项目里面,成千上万进行开发,有一块存储空间(堆), 这块空间里面有一些数据,这些不单只是我使用,我要用,你也用,他也要用,假如说我是用完了这块数据,我不可以释放它,因为我不确定其他人有没有正在使用; 那么出现一个问题:什么时候才能释放?
生活映射:
10个人在森林烧烤, 好不容易把火弄起来,突然有一个人说有事先走, 假如要走的人把火弄灭了, 其它人会有什么反应?
杀了他的心都有,有没有办法,中途有人离开,保证火不会灭, 当所有走了之后, 森林不会发生火灾;
解决方法:
计数器count记录人数, 当中途有人加入, count++, 中途有人离开, count- -, 当count == 0, 把火灭掉;
引用计数
对象: alloc ——》 堆区;
每一个对象里面都有一个引用计数器count, 记录被多少人正在使用;
对于一块动态申请的内存(对象),有一个人(指针)使用,就给这个内存的计数器加1,使用完成后,就给这个计数器减1,当这个内存的引用计数为0了,我们再释放他,这样,上面的问题就解决了。OC,就是使用引用计数这种方式来管理内存的。
⭐️内存管理的黄金法则
1,凡是用alloc,retain,new(或者以new开头的方法),copy(或者copy开头的方法),mutableCopy(或者muTableCopy开头的方法)创建的对象,都需要用release或者autorelease释放。
2,谁创建谁释放(那个类创建,那个类释放,谁写alloc,谁写release)
4.如何将工程改为MRC
点击工程—Build settings—> 搜索gar—> 把“ Automatic Reference Counting“ 改为 NO
5.Chatroom实例
Chatroom.m:
-(void)release
{
[super release];
}
main.m
Chatroom *xiaoming=[[Chatroom alloc]init];
NSLog(@"%ld",xiaoming.retainCount);
Chatroom *xiaogang=xiaoming.retain; //retain 引用计数器加1
NSLog(@"%ld",xiaogang.retainCount);
Chatroom *xiaofang=xiaoming.retain;
NSLog(@"%ld",xiaofang.retainCount);
[xiaoming release];
xiaoming=NULL;
[xiaogang release];
xiaogang=NULL;
[xiaofang release];
xiaofang=NULL;
6.分析
1.alloc/new会导致引用计数+1
2.release 会导致引用计数-1
3.对象在使用完成之后不会自动销毁,如果不释放会内存泄露
4.已经释放的数据再次使用/释放(过度释放)会崩溃,通常会出现 Thread 1:EXC_BAD_ACCESS
'(code=EXC_I386_GPFLT)错误,这是野指针错误,因为你访问了一块已经不属于你的内存
解决办法:[obj release]; obj = nil;因为给空对象发送消息是不引起错误的
5.对象被释放的时候会调用自己类的delloc方法
7.内存管理知识点
ARC和MRC的关系
ARC是编译器特性,不是运行时特性.简单说就是代码在编译的时候自动加入了retain/release/autorelease,原先需要手动添加的用来处理内存管理的引用计数的代码可以自动地由编译器完成了.因此ARC和MRC性能是一样的,有些时候还能更快,因为编译器还可以执行某些优化
8.循环引用
1.定时器导致的循环引用
定时器在内部会引用self,导致self在释放的时候并不会释放掉,因此在释放对象之前需要先把定时器给关闭掉.释放的代码[_timer invalidate];_timer = nil;在delloc方法中调用无效,一般在viewDidDisappear中关闭定时器.
2.代理导致的循环引用 A,B,C
在A中创建B和C,引用计数分别为:A1,B1,A.delegate = B,引用计数变为:A1,B2.如果A释放,B释放,那么B变为A,导致A.delegate也是1,所以A释放不掉,B也没释放掉.
解决办法就是:delegate用assign修饰
3.block导致的循环引用
9.内存优化:
1.广告页或者轮播视图封装,图片非常多的时候,可能会导致内存溢出,优化:视图复用,图片压缩。
2.不要创建太多子视图
3.NSDateFormmater,NSCalender等对象,多次使用要复用