Jay*_*yas 53
正如juul所述,引用类型存储在堆中,而值存储在堆栈中......
在这里,我想解释为什么......
堆栈和堆?
堆栈用于静态内存分配,堆用于动态内存分配,两者都存储在计算机的RAM中.
在堆栈上分配的变量直接存储到存储器中,并且对该存储器的访问非常快,并且在编译程序时处理它的分配.当函数或方法调用另一个函数,该函数又调用另一个函数等时,所有这些函数的执行将保持挂起,直到最后一个函数返回其值.堆栈始终以LIFO顺序保留,最近保留的块始终是要释放的下一个块.这使得跟踪堆栈非常简单,从堆栈中释放块只不过是调整一个指针.
在堆上分配的变量在运行时分配了内存并且访问此内存有点慢,但堆大小仅受虚拟内存大小的限制.堆的元素彼此之间没有依赖关系,并且可以随时随机访问.您可以随时分配一个块并随时释放它.这使得在任何给定时间跟踪堆的哪些部分被分配或释放变得更加复杂.
对于转义关闭: - 要记住的一个重要注意事项是,如果在闭包中捕获存储在堆栈上的值,该值将被移动到堆,以便在执行闭包时它仍然可用.
Juu*_*uul 16
类(引用类型)在堆中分配,值类型(如Struct,String,Int,Bool等)存在于堆栈中.有关更详细的答案,请参阅此主题:为什么选择Struct Over Class?
yoA*_*ex5 10
堆栈与堆
Stack
是线程的一部分。它由按 LIFO 顺序的方法(函数)框架组成。方法框架仅包含局部变量。实际上,它是您在调试或分析错误[关于]期间看到的方法堆栈跟踪。
Heap
ARC [关于]发挥作用的记忆的另一部分。这里分配内存需要更多的时间(找到合适的地方并以同步方式分配)。
Xcode 建议您使用下一个变体Debug Memory Graph
*要查看回溯,请使用:
Edit Scheme... -> <Action> -> Diagnostics -> Malloc Stack Logging
Run Code Online (Sandbox Code Playgroud)
小智 7
通常,当我们问这样的问题(是堆栈还是堆)时,我们关心性能,并希望避免堆分配的过高成本。遵循“引用类型是堆分配的,值类型是堆栈分配的”一般规则可能会导致次优的设计决策,需要进一步讨论。
人们可能会错误地得出这样的结论:传递结构(值类型)通常比传递类(引用类型)更快,因为它不需要堆分配。事实证明这并不总是正确的。
重要的反例是协议类型,其中具有值语义(结构)的具体多态类型实现协议,就像这个玩具示例一样:
protocol Vehicle {
var mileage: Double { get }
}
struct CombustionCar: Vehicle {
let mpg: Double
let isDiesel: Bool
let isManual: Bool
var fuelLevel: Double // gallons
var mileage: Double { fuelLevel * mpg }
}
struct ElectricCar: Vehicle {
let mpge: Double
var batteryLevel: Double // kWh
var mileage: Double { batteryLevel * mpge / 33.7 }
}
func printMileage(vehicle: Vehicle) {
print("\(vehicle.mileage)")
}
let datsun: Vehicle = CombustionCar(mpg: 18.19,
isDiesel: false,
isManual: false,
fuelLevel: 12)
let tesla: Vehicle = ElectricCar(mpge: 132,
batteryLevel: 50)
let vehicles: [Vehicle] = [datsun, tesla]
for vehicle in vehicles {
printMileage(vehicle: vehicle)
}
Run Code Online (Sandbox Code Playgroud)
请注意,CombustionCar
和ElectricCar
对象具有不同的大小,但我们可以将它们混合在一系列Vehicle
协议类型中。这就提出了一个问题:数组容器元素不需要具有相同的大小吗?如果编译器在编译时并不总是知道元素大小,那么它如何计算数组元素的偏移量?
事实证明,这背后隐藏着相当多的逻辑。Swift 编译器将创建所谓的Existential Container
. 它是一个固定大小的数据结构,充当对象的包装器。这个容器被传递给函数调用(被压入堆栈)而不是实际的结构。
Existential Container
长五个字:
| |
|valueBuffer|
| |
| vwt |
| pwt |
Run Code Online (Sandbox Code Playgroud)
前三个单词称为 the valueBuffer
,这是存储实际结构的地方。好吧,除非结构大小大于三个字 - 在这种情况下,编译器将在堆上分配结构并将对其的引用存储在valueBuffer
:
STACK STACK HEAP
| mpge | | reference |-->| mpg |
|batteryLevel| | | | isDiesel |
| | | | | isManual |
| vwt | | vwt | | fuelLevel |
| pwt | | pwt |
Run Code Online (Sandbox Code Playgroud)
因此,将这样的协议类型对象传递给函数实际上可能需要堆分配。编译器将进行分配并复制值,因此您仍然可以获得值语义,但成本会根据您的结构体长度是否为 3 个字或更长而有所不同。这使得“值类型在堆栈上,引用类型在堆上”并不总是正确的。
归档时间: |
|
查看次数: |
16762 次 |
最近记录: |