c内存管理再理解,内存管理机制简述

2019-09-11 05:20 来源:未知

前言:本猿做了将近5年的ios开发,之前用了三年的手动释放来开发应用,正当自己觉得自己对ios内存管理用的炉火纯青的时候,苹果推出了ARC, 一开始可能和大多数猿类一样,对其嗤之以鼻。认为它不如手动释放效率高。后来经过一段时间,大家开始慢慢深入的认识了ARC后,开始意识到他的好处。用ARC开发出来的应用的稳定性非MRC所能比拟。于是没法办,开始随波逐流,匆匆的开始使用起了ARC,从大多数论坛上看到大家对ARC的认识就是:苹果在编译的时候会自动帮你加上release....。哦,原来这么简单,原来就是在MRC的基础上,编译器自己帮你加上release,原来需要release的地方,就不需要写了。两年多来,我就是抱着这样的理解用着ARC,直到今天以前!这两天闲着没事,重新研究了一些代码,发现按照之前的思路,有些内存问题根本解释不通,如是抓紧又看了几篇关于ARC的文章,并写了一些测试代码,才恍然大悟,原来很多网友和我之前对ARC的理解大错特错了。于是,写一下内容重新梳理一下对ARC和MRC的认识...

原理:
  • 每一种对象内部都封存了三个与之相关联的卡尺头,称为引用计数器(auto reference count)
  • 每当使用alloc、new只怕copy创立四个指标时,对象的援用计数器棉被服装置为1
  • 给指标发送一条retain音信(即调用retain方法),能够使援引计数器值+1
  • 给目的发送一条release音信,可以使引用计数器值-1
  • 当三个指标的引用计数器值为0时,那么它将被销毁,其占用的内存被系统回收,OC也会自动向指标发送一条dealloc新闻。一般会重写dealloc方法,在此处释放相关财富。一定毫无一向调用dealloc方法。
  • 可以给目的发送retainCount音讯得到当前的援用计数器值。

苹果的MRC使用的是内存计数器的方式管理,本人觉得用一个比喻来理解非常恰当,在MRC中内存就像一条狗,开发者这就是条狗的主人,每次作计数加1的操作就相当于给狗多栓了一根绳子,每次作计数器减1操作就相当于给狗解掉一根绳子,当所有绳子都解开的时候,狗就跑了,内存就被系统回收了。

主导原则:

MRC:

  • 内存管理遵从“哪个人成立,何人释放,哪个人援引,哪个人管理”的编写制定,当通过alloc、new大概(mutable)copy来成立一个指标,必须调用release或autorelease(autorelease是延迟释放内部存款和储蓄器,不用你本身去手动释放,系统会掌握在哪些时候该去自由掉它。),当通过retain引用三个目的的时候,须求调用release。当对象援用计数为0时,系统将释放该指标,那是OC的手动管理内部存款和储蓄器机制。

ARC:

  • iOS 5.0过后援用自动管理机制——自动引用计数,处理机制与手动机制同样,只是不再需求调用retain、release、autorelease;它编写翻译时的特色,当你使用ARC时,在合适地点插入release和autorelease;它征引strong和weak关键字,strong修饰的指针变量指向对象时,当指针指向新值或者指针不复存在,相关联的对象就会自动释放,而weak修饰的指针变量指向对象,当对象的拥有者指向新值或者不存在时weak修饰的指针会自动置为nil。
  • 假定利用alloc、copy(mutableCopy)大概retian三个目的时,你就有职务,向它发送一条release恐怕autorelease新闻。别的艺术创设的对象,无需由你来保管内存。
  • 向叁个指标发送一条autorelease新闻,这几个指标并不会立马销毁,而是将以此指标纳入了自动释放池,待池子释放时,它会向池中每贰个指标发送一条release音讯,以此来释放对象。
  • 向一个指标发送release消息,并不代表那个目的被灭绝了,而是当以此指标的援引计数为0时,系统才会调用dealloc方法,释放该对象和目的自己它所具备的实例。
  • alloc,new,copy:系统会回来一块计数器为1的新内部存款和储蓄器,相当于卖狗的人给了您一条已经栓好一根绳索的狗
  • retain:会对内部存款和储蓄器的计数器加1,相当于给狗加一条绳子
  • release:会对内部存款和储蓄器计数器减1,相当于给狗解一条绳子
  • autorelease:会在某该函数栈结束后对该内存计数器减1,也就是给家狗解开了绳子,可是小狗未来还在吃食,你不要管它了,它吃完食后发觉绳索没了会自动跑开的。
注意事项:
  • 若是二个指标有几个strong类型的指针指向着,那个目的就不会被保释。倘诺三个指南针指向超越了它的功能域,就能被针对nil。假使三个指针被指向nil,那么它原先指向的靶子就被释放了。当三个视图调控器释放时,它里面包车型地铁大局指针会被针对nil。
  • 有的变量:出了功能域,指针会被置为nil。
  • 主意内部创设对象,外界使用供给增加autorelease。
  • Xib连线的时候,用weak修饰。
  • 代理MRC使用assign修饰,ARC使用weak修饰。
  • block使用copy修饰。
  • block中为了幸免循环引用(常见self持有的block)难点,使用__weak方式。
  • 声称属性时,不要以new开端。假使非要以new开头命名属性的名字,须求和睦定制get方法名,如:
    @property(getter = theString) NSString *newString;
  • 假如要动用自动释放池,用@autoreleasepool{} 。
  • ARC只能管理Foundation框架的变量,若是程序中把Foundation中的变量强制换来COre Foundation中的变量必要交流处理权。
  • 在非ARC工程中运用ARC去编写翻译有些类:-fobjc-arc。
  • 在ARC下的工程应用非ARC去编写翻译有些类:-fno-fobjc-arc。

之前我认为ARC就是从MRC加了一个智能点编译器,现在我觉得ARC的思想和MRC的思想完全是不同的,学习ARC的时候如果完全忘记MRC会更好理解。MRC是以开发者为核心,而ARC是以内存为核心。我们用氢气球来比喻ARC下的内存,ARC下的内存就象底下栓着一根线的很大氢气球,气球下面有两种人,一种是有手的正常人,他们会用手拉着气球,也有很多人没有手的残疾人,他们只能围观着气球。但是只要有一个人拉着它,气球就不会飞走。否则气球就会飞走,气球飞走了,那些围观的人就都会散了。

MRC内存管理测量试验:
Student类:
@interface Student : NSObject {  
    int age;  
}  
@property int age;  
@end 

@implementation Student  
@synthesize age;  
//重写dealloc方法,当引用计数器(auto reference count)为零的时候调用。  
- (void)dealloc {  
    NSLog(@"%@被销毁了",self);  
    [super dealloc]; 
}  
@end  

Controller类:
Student *stu = [[Student alloc]init];// alloc一次,引用计数器为1  
// Student *stu = [[[Studnet alloc]init] autorelease];// 这样写的话系统会在适当的地方对stu的内存进行自动回收,就不用自己写release回收了
// z代表无符号  
NSLog(@"count:%zi", [stu retainCount]);  
[stu retain];// 引用计数器变为2  
NSLog(@"count:%zi", [stu retainCount]);  
[stu release];// 引用计数器变为1  
NSLog(@"count:%zi", [stu retainCount]);          
[stu release];// release一次,引用计数器减1,变为0然后会调用dealloc方法

运行结果:
2017-04-20 23:51:51.041 **[93035:36023785] count:1
2017-04-20 23:51:51.041 **[93035:36023785] count:2
2017-04-20 23:51:51.041 **[93035:36023785] count:1
2017-04-20 23:51:51.041 **[93035:36023785] <Student: 0x100109a80>被销毁了

------随笔

  • ARC下的指针是有项目的,分为strong,weak两体系型的指针。这一点MRC下并从未,MRC下指针未有项目之分。
  • alloc,new,copy:在ARC中那八个操作,就也正是从卖音乐球人手里买来二个引爆气球,但那是你必须找一个有手的人来拉着那个魔术气球,不然买来就飞走了。
  • strong:strong类型的指针就是那种有手的人,将一个strong类型的指针指向一块的内部存款和储蓄器的时候,他就能够拉着它。*weak:weak类型的指针正是从未手的人,他们指向一块内部存款和储蓄器的时候,只会瞧着它,并不可能拉住他。
  • 主若是编写翻译器并不会给您作什么release操作,因为arc里一向未有release那东西。在ARC里面系统只做了这三件事1.在变量效率域甘休时,将变量置为nil2.在一块内部存款和储蓄器没有strong类型指针指向的时候,释放内部存款和储蓄器,并将装有指向这快内部存款和储蓄器的weak指针置nil3.一个指针私下认可注明出来是strong类型
 -  test { //array1,array2默认是strong类型指针 NSArray *array1; NSArray *array2; //weak1,weak2是weak类型指针 NSArray *__weak weak1; NSArray *__weak weak2; //系统申请了@"aaa",@"bbb"两块内存分别交给有手的array1和array2 array1 = [[NSArray alloc] initWithObjects:@"aaa", nil]; array2 = [[NSArray alloc] initWithObjects:@"bbb", nil]; //没有手的weak1,weak2分别看向@"aaa",@"bbb"两个气球 weak1 = array1; weak2 = array2; //array1放弃了@"aaa",转而拉住了@"bbb" array1 = array2; //现在只剩下weak1看着@"aaa", 但没有人拉住@"aaa",所以@"aaa"被系统释放了,weak1被置nil了 NSLog(@"%@", weak1); //输出null //而@"bbb"现在还有两个人拉着,所有内存还在,那么@"bbb"什么时候会释放呢? NSLog(@"%@", weak2); //输出@"bbb"` //整理array1,array2的作用域结束了,被系统制为nil。@"bbb也就释放了" //array1 = nil; //array2 = nil; }
TAG标签:
版权声明:本文由990888藏宝阁发布于编程算法,转载请注明出处:c内存管理再理解,内存管理机制简述