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:
相关推荐
星辰即远方3 小时前
计算器仿写总结
学习·ui·ios·cocoa·xcode
2501_915909067 小时前
全面解析iOS应用上架到App Store的完整流程与关键注意事项
android·macos·ios·小程序·uni-app·cocoa·iphone
00后程序员张8 小时前
抓包鹰 电脑本机网络连接表怎么看?哪些程序在联网 进程归属与可疑 IP 追溯
网络协议·计算机网络·网络安全·ios·adb·https·udp
2501_9159184110 小时前
免 Xcode 开发 iOS,工具链替代方案与编译、签名、安装
ide·vscode·macos·ios·个人开发·xcode·敏捷流程
初级代码游戏11 小时前
iOS开发 Swift 速记5:高级运算符
ios·移动开发·swift
初级代码游戏12 小时前
iOS开发 Swift 速记4:函数与闭包
开发语言·ios·swift
2501_9151063213 小时前
iOS 证书类型及作用说明 账号证书与签名配置的完整解读
android·ios·小程序·https·uni-app·iphone·webview
凡泰AI14 小时前
如何通过小程序多端框架,让一个小程序同时运行在iOS、安卓、鸿蒙以及PC客户端,实现一次开发多端运行的效果
android·ios·小程序
ZacJi1 天前
当苹果将系统 API 划归 @MainActor:一次跨 SDK 版本的 Swift 并发踩坑与破局实战
ios·swift
mardelan1 天前
2026年iOS短视频总结工具测评强识别提效率 整理清晰更省心
ios·音视频