OC学习第九天_内存管理机制

⼀、内存管理介绍
为什么要使⽤内存管理
iOS应⽤程序出现Crash(闪退),90%以上的原因是内存问题。
在⼀个拥有数⼗个甚⾄是上百个类的⼯程⾥,查找内存问题极其困难。了解内存常⻅问题,能帮我们减少出错⼏率。
内存问题体现在两个⽅⾯:内存溢出、野指针异常。

内存管理的⽅式
垃圾回收(gc)
MRC(Manual Reference Count)
ARC(Auto Reference Count)

(1).垃圾回收:程序员只需要开辟内存空间,不需要⽤代码显⽰地释放,系统来判断哪些空间不再被使⽤,并回收这些内存空间,以便再次分配。整个回收的过程不需要写任何代码,由系统⾃动完成垃圾回
收。Java开发中⼀直使⽤的就是垃圾回收技术。

(2).Manual Reference Count,⼈⼯引⽤计数:内存的开辟和释放都由程序代码进⾏控制。相对垃圾回收来说,对内存的控制更加灵活,可以在需要释放的时候及时释放,对程序员的要求较⾼,程序员要熟悉
内存管理的机制。
内存管理的⽅式
(3)Auto Reference Count,⾃动引⽤计数:iOS 5.0的编译器特性,它允许⽤户只开辟空间,不⽤去释放空间。它不是垃圾回收!它的本质还是MRC,只是编译器帮程序员默认加了释放的代码。
iOS的内存管理
iOS⽀持两种内存管理⽅式:ARC和MRC。
MRC的内存管理机制是:引⽤计数。
ARC是基于MRC的。

⼆、内存管理机制
引⽤计数
C语⾔中,使⽤malloc和free,进⾏堆内存的创建和释放。堆内存只有正在使⽤和销毁两种状态。实际开发中,可能会遇到,两个以上的指针使⽤同⼀块内存。C语⾔⽆法记录内存使⽤者的个数。

OC采⽤引⽤计数机制管理内存,当⼀个新的引⽤指向对象时,引⽤计数器就递增,当去掉⼀个引⽤时,引⽤计数就递减。当引⽤计数到零时,该对象就将释放占有的资源。
**影响引⽤计数的⽅法
+alloc
-retain
-copy
-release
-autorelease**
+alloc:开辟内存空间,让被开辟的内存空间的引⽤计数变为1。这是由0到1的过程。
-retain:引⽤计数加1,如果内存空间之前引⽤计数为1,ratain之后变为2,如果引⽤计数是5,retain之后变为6。
-copy:把某⼀内存区域的内容拷⻉⼀份,拷⻉到新的内存空间⾥去,被拷⻉区域的引⽤计数不变,新的内存区域的引⽤计数为1。
-release:引⽤计数减1,如果内存空间之前引⽤计数为4,release之后变为3,如果之前引⽤计数为1,release之后变为0,内存被系统回收。
-dealloc是继承⾃⽗类的⽅法,当对象引⽤计数为0的时候,由对象⾃动调⽤。
我们可以在dealloc中打印⼀句话,验证对象引⽤计数是否降为0.
可以在子类中去复写这个方法

//  书写规范 一定要写在类的最上面
//  系统自动调用释放对象
- (void)dealloc
{
    //  如果重写 dealloc方法必须调用父类的方法,保证对象可以被释放
    //  如果你要在dealloc中使用对象的话
    //  一定要卸载 [super dealloc] 上面
    //  避免产生野指针
    NSLog(@"哈哈被释放了");
    [super dealloc];

}

-autorelease:未来的某⼀时刻引⽤计数减1。如果内存之前引⽤计数为4,autorelease之后仍然为4,未来某个时刻会变为3,是配合自动释放池一起使用的.
autoreleasepool的使⽤
通过autoreleasepool控制autorelease对象的释放。

// 向⼀个对象发送autorelease消息,这个对象何时释放,取决于
// autoreleasepool。
//  autoreleasepool的使⽤
//  创建一个自动释放池的类的对象
NSAutoreleasePool *pool= [[NSAutoreleasePool alloc]init];      // 此时 autorelease的对象引⽤计数1
Person *p = [[Person alloc]init];//p的引用计数为1
[p retain];      //p的引用计数为2
[p autorelease]; //此时p引用计数为2 未来的某个时刻释放
[pool release]; //此时 autorelease的对象引⽤计数0,被释放
//  retainCount方法可以打印出一个对象的当前的引用计数的值
NSLog(@”%d”,[p retainCount]);  //打印结果为1

//  现在不用成对写,用@autoreleasepool {}表示一个释放池,{}内部写操作,出了这个{}就对其中autorelease的对象引用计数减一
@autoreleasepool {
        <#statements#>
    }

NSAutoreleasePool *pool= [[NSAutoreleasePool alloc]init];和[pool release];就像⼀对括号,[xxx autorelease];必须写在两者之间。[xxx autorelease];出现在了两者之间,pool就会把接收autorelease的对象给保存起来(以栈的⽅式,把对象压⼊栈)当[pool release];的时候,pool会向之前保存的对象逐⼀发送release消息(对象出栈,越晚autorelease的对象,越早接收release消息)。autoreleasepool的使⽤
在iOS5之后,不再推荐使⽤NSAutoreleasePool类,使⽤
@autoreleasepool{}替代。
之前写在NSAutoreleasePool *pool= [[NSAutoreleasePool
alloc]init];和[pool release];之间的代码,需要写在
@autoreleasepool{}的⼤括号⾥。
出了⼤括号,⾃动释放池才向各个对象发送release消息。

三、内存管理原则
内存管理的原则
引⽤计数的增加和减少相等,当引⽤计数降为0之后,不应该再使⽤这块内存空间。凡是使⽤了alloc、retain或者copy让内存的引⽤计数增加了,就需要使⽤release或者autorelease让内存的引⽤计数减少。在⼀段代码内,增加和减少的次数要相等。
四、copy
copy⽅法
-跟retain不同,⼀个对象想要copy,⽣成⾃⼰的副本,需要实现NSCopying协议,定义copy的细节(如何copy)。如果类没有接受NSCopying协议⽽给对象发送copy消息,会引起crash。
Person类copy⽅法的实现

//  当你使用copy方法时,首先会自动调用copyWithZone的方法
//  实现拷贝协议的方法
//  copy方法 对引用计数有影响
//  主要取决于你自己的想法
//  就是复写copyWithZone的方法实现

-(id)copyWithZone:(NSZone *)zone
{
    //  伪拷贝 拷贝完还是一个对象(直接返回)引用计数是没有变化的   //  return self;   

    //  浅copy
    //  拷贝后 有两个对象 但是他们的值是同一个值 引用计数有变化
    //  被拷贝的对象不变,拷贝出的新对象计时器从0 变成 1
    //  深copy 首先拷贝出新对象,并且 对象指也重新拷贝一份 再赋值
    //  对字符串进行拷贝 要看字符串这个类如何实现copy方法 对不可变字符串的copy 其实相当于直接 retain 一次
    //  引用计数有变化被拷贝的对象不变,拷贝出的新对象计时器从0 变成 1用
    //  可变字符串 拷贝是 就是真copy了一个新的出来
    NSString *name = [_name copy];
    Person *p = [[Person alloc]initWithName:name          age:_age];
    return p;
}



Person.h⽂件
@interface Person : NSObject<NSCopying>
@property(nonatomic, retain)NSString *name;
@property(nonatomic, assign)int age;
@end

深浅拷贝的图示比较:
课程总结
OC借助引⽤计数机制去管理内存,凡是使⽤了alloc、copy,retain等⽅法,增加了引⽤计数,就要使⽤release和autorelease减少引⽤计数,引⽤计数为0的时候,对象所占的内存,被系统回收。autorelease是未来某个时间(出autoreleasepool)引⽤减⼀,不是即时的。
不是任何对象都可以接收copy消息,只有接受了NSCopying协议的对象才能接收copy消息。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值