iOS开发---内存管理与引用计数

2019-08-18  本文已影响0人  祀梦_

概要

内存管理的思考方式

思考方式

对象操作与OC中方法的对应

对象操作 OC中方法
生成并持有对象 alloc/new/copy/mutableCopy等
持有对象 retain
释放对象 release
废弃对象 dealloc

你看倒这些方法估计会一脸懵逼,我会在后面通过源码方式解释这几个方法。

自己生成的对象,并自己持有

alloc

//自己生成并持有对象
id obj = [[NSObject alloc] init];

//指向生成并持有对象的指针被赋值给obj

new

//自己生成并持有对象
id obj = [[NSObject alloc] init];

//[[NSObject alloc] init] 与 [NSObject new]方法完全一致

copy与mutableCopy

非自己生成的对象,自己也能持有

retain

//取得非自己生成并持有的对象
id obj = [NSMutableArray array];

//NSMutableArray类变量被赋值给obj,但是obj自己并不持有该对象。
[obj retain];

//现在obj持有该对象

//通过retain方法,非自己生成的对象跟用alloc方法生成并持有的对象一样。

不再需要自己持有的对象时释放

release

//自己生成并持有对象
id obj = [[NSObject alloc] init];

[obj release];
//释放对象
//指向对象的指针仍然被保留在变量obj中,貌似能访问,但对象一经释放绝对不可访问。

//通过release方法,只要是自己持有某个对象,使用release方法都可以释放

无法释放非自己持有的对象

alloc/retain/release/dealloc底层实现

GNU源码

alloc

+ (id)alloc {
  return [self allocWithZone:NSDefaultMallocZone()];
}

+ (id)allocWithZone:(NSZone *)z {
  return NSAllocateObject(self, 0, z);
}
//通过allocWithZone:类方法调用了NSAllocateObject函数分配对象

struct obj_layout {
  NSUInteger retained; 
}

inline id 
NSAllocateObject (Clasee aClass, NSUInterger extraBytes, NSZone *zone) {
  int size = 计算容纳对象所需内存大小
  id new = NSZoneMalloc(zone, size);
  memset(new, 0, size);//把分配的内存全部置为0
  new = (id)&((struct obj_layout *) new)(1);
}

//其中NSDefaultMallocZone和NSZoneMalloc中NSZone时为了防止内存碎片化而引入的结构。
//然而现在内存管理本身已经极具效率,使用区域来管理内存反而会引起内存使用效率低下

retain

- (id)retain {
  NSIncrementExtraRefCount(self);
  return self;
}

inline void 
NSIncrementExtraRefCount (id anObject) {
  if (((struct obj_layout *) anObject)[-1].retained == UINT_MAX - 1) {
    [NSException raise: NSInternalInconsistencyException format:@"NSIncrementExtraRefCount () asked to increment too far"];
  }//如果retained变量超过最大值时发生异常的代码
  ((struct obj_layout *) anObject)[-1].retained++;
}

release

- (void)release {
  if (NSDecrementExtraRefCountWasZero(self)) {
    [self dealloc];
  }
}

BOOL
NSDecrementExtraRefCountWasZero(id anObject) {
  if((struct obj_layout *) anObject)[-1].retained == 0) {//如果引用计数已经为0时,调用release方法直接废弃该对象
        return YES;
  } else {
    (struct obj_layout *) anObject)[-1].retained--;//如果引用计数不为0,引用计数减一;
    return NO;
  }
}

dealloc

- (void)dealloc {
  NSDeallocateObject(self);
}

inline void
NSDeallocateObject(id anObject) {
  struct obj_layout *o = &((struct obj_layout *) anobject)[-1];
  free(o);//仅仅废弃有alloc分配的内存
}

苹果实现

autorelease

什么是autorelease

GNU源码

苹果实现

class AutoreleasePoolPage {
  static inline void *push() {
    相当于生成或持有NSAutoreleasePoolPage对象
  }
  
  static inline void *po() {
    相当于废弃NSAutoreleasePool类对象
      releaseAll();
  }
  
  static inline id autorelease (id obj) {
    相当于NSAutoreleasePool类 的addObject类方法
    AutoreleasePoolPage *autoreleasePoolPage = 取得正在使用的AutoreleasePoolPage实例 ;
    autoreleasePoolPage->add(obj)
  }
  
  id *add(id obj) {
    将对象追加到内部数组
  }
  
  void releaseAll() {
    调用内部数组中对象 的release方法
  }
}
上一篇 下一篇

猜你喜欢

热点阅读