Object-C内存管理解析一

2020-04-17  本文已影响0人  KOLee

一、关于引用计数:

读了《Objective-C高级编程(iOS与OS X多线程和内存管理)》,发现吊炸天的感觉,所以记录下。嗯 还是自己太菜了,好像是7年前的书了。 自己尽然没有去认真的去研读,惭愧,惭愧!

最早进入办公室的人开灯 ->最后离开办公室的人关灯
中间进入就是++,离开--

1.自己生成的对象,自己持有
2.非自己生成的对象,自己也能持有
3.不需要自己持有持有的对象时释放
4.非自己持有的对象无法释放
以上就是对引用计数的概括,有点枯燥,但是把内存管理读完再来看,就非常美妙。

二、alloc/retain/release/dealloc实现

1.alloc方法的实现

-在base/Source/Foundation/NSObject.m的+ (id) alloc方法里,最后调用

NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone)
// 简化后主要代码

// size:计算容纳对象所需内存的大小 
//obj_layout:保存着引用计数retained 
// 苹果用哈希表实现 GNUstep用占用头部内存实现
 int size = class_getInstanceSize(aClass) + extraBytes + sizeof(struct obj_layout);
  if (zone == 0)
    {
      // NSZone是为防止内存碎片化引入的结构,对内存分配区域进行多重化管理
      // 根据对象的目的、大小、分配
      zone = NSDefaultMallocZone();
    }
    // 给对象分配内存空间
  new = NSZoneMalloc(zone, size);
  if (new != nil)
    {
     // 将内存空间置为0
      memset (new, 0, size);
      new = (id)&((obj)new)[1];
      object_setClass(new, aClass);
      AADD(aClass, new);
    }
  // 返回对象指针
  return new;
2.retain方法的实现
static id retain_fast(id anObject)

1.weak修饰的时候返回本身不做处理
2.static id objc_retain_fast_np_internal(id anObject)主要的就是 ((obj)anObject)[-1].retained++;
3.这里说明一下 ((obj)anObject)[-1]GNUstep用占用头部内存实现,就是obj返回的指针-1就是指向retained的内存地址,苹果用哈希表实现会有点不同

3.release方法的实现

-在base/Source/Foundation/NSObject.m的- (oneway void) release方法里,最后调用

static void release_fast(id anObject)

1.weak修饰的时候返回本身不做处理
2.引用计数--((obj)anObject)[-1].retained--
3.引用计数为0时调用dealloc方法

4.dealloc方法的实现

-在base/Source/Foundation/NSObject.m的- (void) dealloc方法里

NSDeallocateObject(id anObject)
// 简化后代码

NSDeallocateObject(id anObject)
{
  // 获取类对象
  Class aClass = object_getClass(anObject);
   // 判断 当前类对象 元类对象不为空
  if ((anObject != nil) && !class_isMetaClass(aClass))
    {
     //ARC下
      obj   o = &((obj)anObject)[-1]; // 获取对象指针
      NSZone    *z = NSZoneFromPointer(o); // tagePoint寻址
      if (NSZombieEnabled == YES)
    {
        // 如果僵尸对象散列表不为空 放进僵尸对象散列表
      if (0 != zombieMap)
        {
              pthread_mutex_lock(&allocationLock);
          NSMapInsert(zombieMap, (void*)anObject, (void*)aClass);
              pthread_mutex_unlock(&allocationLock);
        }
        // 释放僵尸对象 或者 添加僵尸对象
      if (NSDeallocateZombies == YES)
        {
          object_dispose(anObject);
        }
      else
        {
          object_setClass(anObject, zombieClass);
        }
    }
      else
    {
      object_dispose(anObject);
    }
    }
  return;
}
id  object_dispose(id obj)
void *objc_destructInstance(id obj) 
{
    if (obj) {
        // Read all of the flags at once for performance.
        // 判断是否有C++析构函数
        bool cxx = obj->hasCxxDtor();
        // 是否有关联对象
        bool assoc = obj->hasAssociatedObjects();

        // This order is important.
        // 清除有C++析构函数
        if (cxx) object_cxxDestruct(obj);
        // 清除关联对象表 AssociationsManager对应的value
        if (assoc) _object_remove_assocations(obj);
        obj->clearDeallocating();
    }
    return obj;
}

// 判断是否有C++析构函数
bool cxx = obj->hasCxxDtor();
// 是否有关联对象
bool assoc = obj->hasAssociatedObjects();

union isa_t 
struct {
    // 1代表优化后的使用位域存储更多的信息。
    uintptr_t nonpointer        : 1; 

   // 是否有设置过关联对象
    uintptr_t has_assoc         : 1;

    // 是否有C++析构函数
    uintptr_t has_cxx_dtor      : 1;

    // 存储着Class对象的内存地址信息
    uintptr_t shiftcls          : 33; 

    // 用于在调试时分辨对象是否未完成初始化
    uintptr_t magic             : 6;

    // 是否有被弱引用指向过。
    uintptr_t weakly_referenced : 1;

    // 对象是否正在释放
    uintptr_t deallocating      : 1;

    // 引用计数器是否过大无法存储在isa中
    // 如果为1,那么引用计数会存储在一个叫SideTable的类的属性中
    uintptr_t has_sidetable_rc  : 1;

    // 里面存储的值是引用计数器减1
    uintptr_t extra_rc          : 19;
};
上一篇 下一篇

猜你喜欢

热点阅读