Swift中如何判断变量分配在栈还是堆?含SIL分析及结构体示例
Swift结构体栈/堆分配与SIL的alloc_box指令解析
结构体的核心存储规则
Swift中结构体是值类型,默认情况下局部结构体实例会分配在栈上——哪怕结构体包含引用类型成员,也只是结构体本身(包括引用类型的指针)存在栈中,而引用类型的实例对象(比如代码中A()的实例)会单独分配在堆上。以你的代码为例:
class A {} struct B { var val = A() } var someVar = B()
someVar这个B实例本身在栈上,它的val字段是一个指向堆中A实例的指针,A的实际数据存在堆里。
为什么两个结构体初始化SIL都出现alloc_box?
你误解了alloc_box的作用:它不直接代表堆内存分配,而是初始化过程中用于持有可变结构体实例的临时存储容器。因为结构体初始化方法需要修改self的属性(哪怕是默认初始化),Swift会用alloc_box创建一个可变的box来承载初始化中的结构体实例。
在你使用-O优化编译后,编译器会进行逃逸分析和代码优化,这个临时的box大概率会被消除,最终结构体实例还是分配在栈上。你看到的alloc_box只是初始化阶段的中间步骤,和最终的存储位置没有直接对应关系。
如何通过SIL判断栈/堆分配?
想通过SIL确定最终存储位置,需要结合上下文指令分析:
- 栈分配:如果看到
alloc_stack指令创建变量,或者初始化后的结构体实例被直接存储到栈变量中(比如store指令指向栈分配的位置),说明最终在栈上。 - 堆分配:结构体只有在发生逃逸时才会被分配到堆,比如被闭包捕获、传递给
@escaping参数、存入堆存储的容器(如Array)。此时SIL中会出现alloc_heap指令,或者alloc_box的内容被传递到需要堆存储的上下文。
回到你的示例,两个结构体的初始化SIL里的alloc_box都是临时的,最终someVar作为局部变量会被优化到栈上;如果是全局变量,则会存储在静态存储区,既不是栈也不是堆。
内容的提问来源于stack exchange,提问作者Amely
相关产品推荐
相关产品推荐

