iOS Dealloc 在内存管理中的实现机制

1 介绍

在 Objective-C 中,dealloc 方法是用来释放对象资源的。当一个对象被释放时(即引用计数变为零),系统会自动调用该对象的 dealloc 方法。在 dealloc 方法中,可以执行一些清理操作,比如释放对象持有的资源、取消观察者或通知、执行其他的清理操作等。

在 Swift 中,使用 deinit 方法来执行类似的操作。当对象的引用计数降为零时,系统会自动调用该对象的 deinit 方法来执行清理操作。

2 实现机制

2.1 Dealloc 调用流程

  1. 首先调用 _objc_rootDealloc() 方法。
scss 复制代码
- (void)dealloc {
    _objc_rootDealloc(self);
}
  1. 接着调用 rootDealloc() 方法。
arduino 复制代码
objc_object::rootDealloc()
{
    if (isTaggedPointer()) return;

    if (fastpath(isa.nonpointer                     &&
                 !isa.weakly_referenced             &&
                 !isa.has_assoc                     &&
#if ISA_HAS_CXX_DTOR_BIT
                 !isa.has_cxx_dtor                  &&
#else
                 !isa.getClass(false)->hasCxxDtor() &&
#endif
                 !isa.has_sidetable_rc))
    {
        assert(!sidetable_present());
        free(this);
    } 
    else {
        object_dispose((id)this);
    }
}
  1. 在这一步,会判断对象是否可以被释放,主要根据以下五种情况进行判断:
  • NONPointer_ISA:是否为一个固定的非指针值
  • weakly_reference:是否有弱引用
  • has_assoc:是否有关联对象
  • has_cxx_dtor:是否有 C++ 析构函数
  • has_sidetable_rc:是否使用 sidetable 进行引用计数管理

sidetable 是指 Objective-C 中用于管理一些特殊情况下的引用计数的数据结构。在对象的引用计数比较大或者需要支持多线程时,Objective-C 运行时会采用 sidetable 来进行引用计数的管理。sidetable 是一种哈希表的形式,用于存储额外的引用计数,这样可以更高效地管理对象的引用计数。在释放对象时,需要清理 sidetable 中的相关信息,以确保内存正确释放。

  1. 流程处流
  • 如果满足以上任意一种情况,将会调用 object_dispose() 方法进行下一步处理。
  • 如果不满足上述五种情况,则执行释放操作,即调用 C 函数的 free()
  1. 执行完毕。

2.2 object_dispose() 调用流程

scss 复制代码
object_dispose(id obj)
{
    if (!obj) return nil;

    objc_destructInstance(obj);    
    free(obj);

    return nil;
}
  1. 直接调用 objc_destructInstance() 方法。
  2. 然后调用 C 函数 free() 进行内存释放。

2.3 objc_destructInstance() 调用流程

scss 复制代码
void *objc_destructInstance(id obj) 
{
    if (obj) {
        // Read all of the flags at once for performance.
        bool cxx = obj->hasCxxDtor();
        bool assoc = obj->hasAssociatedObjects();

        // This order is important.
        if (cxx) object_cxxDestruct(obj);
        if (assoc) _object_remove_assocations(obj, /*deallocating*/true);
        obj->clearDeallocating();
    }

    return obj;
}
  1. 首先判断是否有 C++ 相关内容(hasCxxDtor),如果有,则调用 object_cxxDestruct() 方法销毁 C++ 相关内容。
  2. 接着判断是否有关联对象(hasAssociatedObjects),如果有,则调用 object_remove_associations() 方法销毁关联对象。
  3. 调用 clearDeallocating() 方法。
  4. 执行完毕。

2.4 clearDeallocating() 调用流程

scss 复制代码
objc_object::clearDeallocating()
{
    if (slowpath(!isa.nonpointer)) {
        // Slow path for raw pointer isa.
        sidetable_clearDeallocating();
    }
    else if (slowpath(isa.weakly_referenced  ||  isa.has_sidetable_rc)) {
        // Slow path for non-pointer isa with weak refs and/or side table data.
        clearDeallocating_slow();
    }

    assert(!sidetable_present());
}
  1. 先执行 sidetable_clearDeallocating() 方法。
  2. 然后执行 weak_clear_no_lock 方法,在这一步骤中,将指向该对象的弱引用指针置为 nil。
  3. 接着执行 table.refcnts.erase() 方法,从引用计数表中擦除该对象的引用计数。
  4. 至此,Dealloc 的执行流程结束。

3 开发问题

ViewController 不执行 dealloc 方法的情况?

  1. 循环引用,例如 block、delegate
  2. 未正确释放资源,例如通知、观察者、NSTimer
  3. 其他
    • 第三方库或框架可能会影响 ViewController 的生命周期,导致 dealloc 方法不被调用。
    • WKWebView 适时移除消息处理程序 removeScriptMessageHandlerForName:
相关推荐
T1an-12 小时前
最右IOS岗一面
ios
坏小虎5 小时前
Expo 快速创建 Android/iOS 应用开发指南
android·ios·rn·expo
光影少年6 小时前
Android和iOS原生开发的基础知识对RN开发的重要性,RN打包发布时原生端需要做哪些配置?
android·前端·react native·react.js·ios
北京自在科技6 小时前
Find My 修复定位 BUG,AirTag 安全再升级
ios·findmy·airtag
Digitally7 小时前
如何不用 USB 线将 iPhone 照片传到电脑?
ios·电脑·iphone
Sim148019 小时前
iPhone将内置本地大模型,手机端AI实现0 token成本时代来临?
人工智能·ios·智能手机·iphone
Digitally21 小时前
如何将 iPad 上的照片传输到 U 盘(4 种解决方案)
ios·ipad
报错小能手1 天前
ios开发方向——swift并发进阶核心 @MainActor 与 DispatchQueue.main 解析
开发语言·ios·swift
LcGero1 天前
Cocos Creator 业务与原生通信详解
android·ios·cocos creator·游戏开发·jsb
ii_best1 天前
lua语言开发脚本基础、mql命令库开发、安卓/ios基础开发教程,按键精灵新手工具
android·ios·自动化·编辑器