单例对象分配在哪里?

Where Singleton object is allocated?

我想知道 myClass 对象的准确分配位置,所以我画了分配流程

class MyClass {
    static let shared = MyClass()
    private init() { }
}

let myClass = MyClass.shared 
  1. myClass 常量分配在堆栈中

  2. myClass 常量指向分配了 MyClass 的堆

  3. MyClass.shared static 属性 指向 MyClass() 在堆中分配的位置

这个流程对吗?我是不是误会了什么?

  • Swift在数据段为MyClass.shared分配存储,初始化为nil。数据段的布局和初始内容由可执行文件定义。从历史上看,堆在数据段的末尾立即开始,但在具有地址 space 布局随机化 (ASLR) 的现代 64 位系统上,我不知道这是否仍然如此。

  • Swift还在数据段分配了一个swift_once_t记录MyClass.shared是否已经初始化

  • Swift在代码段中为MyClass.shared生成一个getter函数。 getter 函数在第一次调用 getter 时使用 swift_once_t 来初始化 MyClass.shared 的存储。它看起来大约是这样的:

    var _storage_MyClass_shared: MyClass? = nil
    var _once_MyClass_shared: swift_once_t = .init() // essentially, false
    
    func _getter_MyClass_shared() -> MyClass {
        swift_once(&_once_MyClass_shared, {
            _storage_MyClass_shared = MyClass()
        })
        return _storage_MyClass_shared!
    }
    
  • MyClass的实例存储在堆上。它以包含 isa 指针(指向 MyClass 元数据)的单词开头,后跟包含(通常)引用计数的单词,然后是对象实例变量的存储。在您的情况下,没有实例变量,因此没有额外的存储空间。图表中标有 Myclass() 的蓝色框和指向它的箭头不存在。

  • 如果 myClass 位于顶层(不在方法或数据类型声明中),那么它也与另一个 swift_once_t 一起存储在数据段中跟踪是否初始化过,Swift在代码段为它生成getter

  • 如果myClass是一个数据类型的实例变量,那么它被存储为它包含对象的一部分,它可能在栈上也可能在堆上(在这种情况下structenum 或元组)或始终在堆上(在 classactor 的情况下)。

  • 如果myClass是一个函数中的局部变量,那么它被存储在堆栈中。