OC的内存管理机制

1. 为什么要使用内存管理

iOS应用程序出现crash(闪退), 90%以上的原因是出现了内存问题!
内存问题主要出现在内存溢出和野指针异常!

内存溢出 iOS给每个应用提供了一定的内存, 用于程序的运行, 一旦超过内存的上限,就会Crash,
野指针异常 对象内存空间已经被系统回收, 然而去还用指针指使用了这块内存!

2. 内存管理的分类

垃圾回收机制(gc);
垃圾回收机制: 程序员只需要开辟内存空间, 不需要用代码去释放! 系统自己来判断那些空间不再被使用, 并且回收这些内存空间以便再次分配, 整个回收的过程不需要写任何代码, 有系统自动完成垃圾回收, java开发中一直使用的就是垃圾回收机制!

MRC(Manual Reference Count) ; 人工引用计数;
人工引用计数: 内存的开辟和释放都是由程序代码进行控制, 相对于垃圾回收机制来说,对内存的控制更加灵活, 可以在需要释放的饿时候及时释放, 对程序员的要求较高, 程序员要熟悉内存的管理的机制!

ARM (Auto Reference Count);
自动引用计数:iOS 5.0的编译器特性, 它允许用户开辟空间, 不用去释放空间, 它不是垃圾回收! 她的本质还是MRC, 只是编译器帮程序员默认加了释放的代码,
iOS 支持MRC和ARC

3. 引用计数

C语言中,使用malloc 和 free 进行堆内存, 进行堆内存的创建和释放, 对内存只有正在使用和销毁两种状态!
实际开发中, 可能遇到两个以上的指针使用同一块内存, C语言无法记录内存使用个数!
OC采用引用计数管理内存, 当一个新的引用指向对象的时候, 引用计数器就递增, 当去掉一个引用时, 引用计数就递减, 当引用计数, 到零的时候, 该对象就是占有的资源!

OC引用技术的方法
  • alloc 引用计数+1;
    Person *p = [[Person alloc] init];
    // 显示引用计数
    NSLog(@"%ld", [p retainCount]); // 引用计数 1

  • retain 引用计数+1
    [p retain];
    NSLog(@"%lu", [p retainCount]); // 引用计数 2;

  • release 引用计数 -1
    [p release];
    NSLog(@"%lu", [p retainCount]); 引用计数 1;

但是, 当p再次release一次的时候,
[p release] // -1 此时p的引用计数为0, 因而对象应该是已被释放的!
NSLog(@"%lu", [p retainCount]); 打印却为1;
打出的引用计数虽然为1, 但他的实际为零, 对象已经被释放的!

  • autorelease autorelease引用计数不是立即 -1, 在未来的某一时刻(出了 autoreleasepool(自动释放池)) 之后, 引用计数再 -1**

通过autoreleasepool控制autorelease对象的释放!
向一个对象发送autorelease消息, 这个对象何时释放, 取决于autoreleasepool(自动释放池子)!

  Person *p2 = [[Person alloc] init]; 
  @autoreleasepool {
  [p2 retain]; 引用计数+1 为2;
  [p2 autorelease]; 此时引用计数为2;
  NSLog(@"%lu", [p2 retainCount]);
  }

NSLog(@"%lu", [p2 retainCount]); // 出了释放池, 计数 -1

  • copy 引用几计数 +1
    对象想使用copy, 必须签订copy协议, 实现copy协议
    person类签订copy协议, 实现copy方法

如下.h 和 .m 文件
Person .h 文件
// 签订copy协议
#import
@interface Person : NSObject
@property(nonatomic, assign)NSString *name;
@property(nonatomic, assign)NSString *age
@end

Person  .m文件  // 必须重写delloc方法, 因为
  #import "Person.h"
  @implementation Person
  // 重写alloc方法
  - (void)dealloc
  {
  NSLog(@"******"); // 定义一个, 用于标记
  [super dealloc];
   }
  // 实现copy协议方法
  - (id)copyWithZone:(NSZone *)zone
  {
  Person *p = [[Person allocWithZone:zone]  init];
  p.name = self.name;
  p.age = self.age;
  return p;
  }

调用!
Person *p3 = [[Person alloc] init];
p3.name = @"tom";
p3.age = @"20";
// 使用copy创建
Person *p4 = [p3 copy];
NSLog(@"--- %d ---", LINE);
NSLog(@"%@, %@", p4.name, p3.age);
NSLog(@"%lu", [p3 retainCount]);
// p4 的引用计数是多少?
NSLog(@"%lu", [p4 retainCount]); // 用copy 计数 会+1;

  • dealloc
    • dealloc是继承自父类的方法,当对象引用计数为0的时候,由对象自动调用。用于释放内存区域;
    • 必须重写delloc方法, 在.m文件中
  • 加入数组的时候, 对象retain一次, 引用计数+1;
    Person *p5 = [[Person alloc] init];
    [arr addObject:p5];
  • 对象移除数组的时候, 对象release一次, 引用计数 -1;
    [arr removeObject:p5];
    添加和删除, 系统内部都帮你实现了!
内存管理原则;
- 引用计数的增加和减少相等,当引用计数降为0之后,不应该再使 用这块内存空间;
- 凡是使用了alloc、retain或者copy让内存的引⽤用计数增加了,就需要使用release或者autorelease让内存的引用计数减少。在一段代码内,增加和减少的次数要相等。 

你可能感兴趣的:(OC的内存管理机制)