美文网首页
Object-C内存管理解析一

Object-C内存管理解析一

作者: KOLee | 来源:发表于2020-04-17 18:37 被阅读0次

一、关于引用计数:

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

  • ARC之前引用计数是得程序员自己管理的,ARC之后是编译器帮我们管理的。但是 是不是就不用了解呢?如果你还在用OC的话绝对用处很大,农村人,不讲套路。
  • 引用计数,引用书中的例子:

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

  • 管理方式:

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

二、alloc/retain/release/dealloc实现

  • 必须先搞定这几个鬼东西,这几个可是OC内存管理的基石,按照惯例,思维导图 怼一发:


    图片.png
  • 密密麻麻,看着是不是很反感。跟着走进去你会发现花姑娘
    因为NSObject不开源,所以这个GNUstep现在是2.7.0版本。这个鬼基本由于NSObject内部实现方法一样,查不了多少,还有一个runtime的源代码也准备好 开搞
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方法的实现
  • 在base/Source/Foundation/NSObject.m的- (id) 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;
}
  • 上面注释写的很清楚了,我主要把非ARC下的代码删了,retain和release主要的说清楚,其他的大家可以自己看看,然后发现object_dispose()方法没有了,不急因为object_dispose()是runtime的东西
  • 在runtime源码objc/Source/objc-runtime-new.mm里面的
id  object_dispose(id obj)
  • 释放之前还调用了objc_destructInstance(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;
}
  • 最后调用了obj->clearDeallocating()可以自己进去看看,思维导图里面注释的比较清楚如图:


    图片.png
  • 至于从何得知void *objc_destructInstance(id obj) 的方法

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

  • 可以根据isa指针联合体里面有记录的,大致如下:
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;
};
  • 今天就到这了,小子头昏眼花,急需按一波。陆续会更新内存管理的内容,各位看官,回见

相关文章

  • Object-C内存管理解析一

    一、关于引用计数: 读了《Objective-C高级编程(iOS与OS X多线程和内存管理)》,发现吊炸天的感觉,...

  • 内存管理初探

    一、概览 1.什么是内存管理 内存管理是在程序运行时,分配内存空间的过程。在Object-C当中,内存管理可以被看...

  • Swift引用计数管理一

    Swift源码之引用计数管理一 标识Object-C或者Swift的内存管理标志类typedef unsigned...

  • Swift中解决引用循环之Unowned 与 Weak的选择

    Swift的内存管理机制与Object-C一样,都是采用了自动内存管理 -- ARC。那么这样就不得不想到老生常谈...

  • Object-C内存管理

    一、引用计数器和对象所有权的基本概念 1、引用计数器 每个对象都会有一个引用计数器,当引用计数器为0是,系统就会将...

  • object-C 内存管理

    程序内存使用情况: object-C可执行的程序是由(可执行)代码、初始化代码和未初始化的程序数据、链接信息、重定...

  • Object-C内存管理

    一.内存布局 如上图,内存布局共分为如下几个区: 内核:由系统控制处理的,大概有占有1个GB 栈:函数、方法、局部...

  • Object-C 内存管理

    一基本原理 Objective-C的内存管理机制与.Net/Java那种全自动的垃圾回收机制是不同的,它本质上还是...

  • ios面试2

    62.谈谈Object-C的内存管理方式及过程? 答: 1).当你使用new,alloc和copy方法创建一个对象...

  • iOS面试题-第十四页

    62.谈谈Object-C的内存管理方式及过程? 答: 1).当你使用new,alloc和copy方法创建一个对象...

网友评论

      本文标题:Object-C内存管理解析一

      本文链接:https://www.haomeiwen.com/subject/eibyvhtx.html