内存管理(上)

来源:互联网 发布:初中生自学编程难吗 编辑:程序博客网 时间:2024/06/01 12:08

一、内存管理的方式
  造成程序崩溃的主要原因:
  1. 野指针:指针所指向的空间已经被回收,但是依然使用该指针访问已经被收回的空间(野指针不会立刻造成程序崩溃)。
  2. 内存溢出:所需内存超过了给定内存的上限。
  3. 内存泄漏:内存已经被开辟,但是没有被释放。
  iOS支持两种内存管理方式:ARC和MRC。
  MRC的内存管理机制是:引用计数。ARC是基于MRC的。
  ARC与MRC的区别:
  MRC:手动引用计数,对象的创建以及对象的所有权的释放都需要我们自己去写代码操作,对我们自己的要求较高。
  ARC:iOS5.0之后出现的,是编译器特性,系统会在合适的位置自动的帮我们添加上release/autorelease代码,我们不需要自己去写代码释放所有权,ARC不是垃圾回收,本质还是MRC。
二、引用计数机制,影响引用计数的各种方法
  OC采用引用计数机制管理内存,每个对象都有一个引用计数器,用来记录当前对象的引用次数。当一个新的引用指向对象时,引用计数器就加1,当去掉一个引用时,引用计数就减1。当引用计数到零时,该对象的空间就被系统回收。
  影响引用计数的方法:

//alloc 使应用计数 0---1.//retain 使引用计数在原有的基础上+1Person *p2 = [p1 retain];NSLog(@"%lu", [p2 retainCount]);Person *p3 = [p2 retain];NSLog(@"%lu", [p3 retainCount]);//注意:引用计数指的是开辟的空间的引用计数,不是指针变量的引用计数,指针变量是没有引用计数的.//release 在引用计数原有的基础上-1(立刻减1).//autorelease 延迟释放,必须和自动释放池结合使用.也是使对象的引用计数-1,但是会在出了离其最近的自动释放池后将引用计数-1[p3 release];NSLog(@"%lu", [p2 retainCount]);[p2 autorelease];NSLog(@"%lu", [p1 retainCount]);[p1 release];//dealloc 回收对象的空间,当对象的引用计数变为0时,该方法会自动调用.如果想查看对象的空间是否被回收,可以重写该方法,但是注意需要调用super.注意:永远不要手动的调用dealloc//copy:新创建一个对象,引用计数由0变成1,原对象的引用计数不发生变换.

  对象的引用计数只有在堆区才是有意义的。

三、内存管理的基本原则
  只要使用了alloc,retain或者copy让内存的引用计数增加了,就需要使用release或者autorelease让内存的引用计数减少。在一段代码内,增加和减少的次数要相等。
  如果增加的次数大于减少的次数,会造成内存泄漏。
  如果增加的次数小于减少的次数,会造成过度释放。
  如果增加的次数等于减少的次数,还继续访问,造成野指针问题。
四、协议
  协议:本质上就是一堆方法的声明,哪个类遵循该协议,该类就需要实现协议中的方法。一个类可以遵循多个协议,每个协议用逗号隔开。
  协议中的方法分两种:必须实现的,用@required关键字修饰。默认的,选择实现的,用@optional关键字修饰。
  实现一个基础版的协议流程:
  1. 创建一个协议(.h文件)。
  2. 声明协议中的方法。
  3. 让某个类遵循协议(导入协议文件,在该类父类名的后面写<协议名>)。
  4. 该类遵循协议后需要实现协议中的方法。
  5. 创建该类对象,执行协议方法。
  示例:
  协议文件:

@protocol MyProtocol <NSObject>@required- (void)sayHello;@optional- (void)sayBye;@end

  .h文件:

#import "MyProtocol.h"@interface Person : NSObject<MyProtocol>@property (nonatomic, copy) NSString *name;@end

  .m文件实现协议方法:

- (void)sayHello{    NSLog(@"你好,妹子,我是%@,请问,这是你掉的板砖吗?", self.name);}- (void)sayBye{    NSLog(@"再见,妹纸~~~~下次再XXXX");}

五、内存拷贝
  拷贝:如果自定的类想要实现copy,必须遵循NSCopying协议,并实现协议中的方法,才可以实现copy,不然会crash。
  根据NSCoping中copyWithZone:方法的实现不同,拷贝分为三种类型:
  1. 伪拷贝:拷贝地址,相当于retain操作,引用计数加1。

- (id)copyWithZone:(NSZone *)zone{    return [self retain];}

  2. 浅拷贝:对象开辟新的空间,但是两个对象的实例变量指向同一块空间。

- (id)copyWithZone:(NSZone *)zone{    Person *p = [[Person allocWithZone:zone] init];    return p;}

  3. 深拷贝:对象开辟新的空间,两个对象的实例变量也指向不同的空间。

- (id)copyWithZone:(NSZone *)zone{    Person *p = [[Person allocWithZone:zone] init];    p.name = [self.name mutableCopy];    return p;}
原创粉丝点击