在 Swift 中家厌,struct 是值類型怎栽,默認情況下是存儲在棧上的,且是連續(xù)內存地址存儲的
分析
定義一個簡單的結構體:
struct Size {
var width: Int
var height: Int
}
可以通過 MemoryLayout
打印 Size 的內存大懈松贰:
var size = Size(width: 1, height: 2)
print("內存對齊: \(MemoryLayout.alignment(ofValue: size))")
print("實際占用的內存大小: \(MemoryLayout.size(ofValue: size))")
print("分配的內存大小: \(MemoryLayout.stride(ofValue: size))")
print("內存對齊: \(MemoryLayout<Size>.alignment)")
print("實際占用的內存大小: \(MemoryLayout<Size>.size)")
print("分配的內存大小: \(MemoryLayout<Size>.stride)")
打印結果為:
內存對齊: 8
實際占用的內存大小: 16
分配的內存大小: 16
內存對齊: 8
實際占用的內存大小: 16
分配的內存大小: 16
在 swift 中故硅,Int 類型占用8個字節(jié)的內存空間,Size 結構體有2個 Int 類型的成員屬性萨螺,Size 結構體的內存模型如下圖所示:
由于結構體是值類型窄做,數據默認存放在棧空間慰技,且是連續(xù)的內存存放椭盏。
初始化一個 size
變量,并打印其內存地址:
var size = Size(width: 1, height: 2)
let rawPointer = withUnsafePointer(to: &size) {
UnsafeMutableRawPointer(mutating: $0)
}
print(rawPointer) // 輸出:0x0000000100004078
可以通過 View Memory 或則 lldb 查看內存:
-
View Memory (
Debug --> Debug Workflow --> View Memory
)
- lldb
驗證
為了進一步驗證結構體是值類型吻商,且值是存放在連續(xù)的內存中的掏颊,下面將通過 UnsafeMutableRawPointer 和 lldb 做驗證
UnsafeMutableRawPointer
我們通過 func storeBytes<T>(of value: T, toByteOffset offset: Int = 0, as type: T.Type)
函數可以修改內存中的值:
// 修改 width 的值為 3
rawPointer.storeBytes(of: 3, as: Int.self)
// 修改 height 的值為 4,height 相對于size的內存起始地址偏移8個字節(jié)(Int的大小)
rawPointer.storeBytes(of: 4, toByteOffset: 8, as: Int.self)
print(size)
在控制臺可以看到對應的輸出為
Size(width: 3, height: 4)
和 storeBytes
函數相對應的有 func load<T>(fromByteOffset offset: Int = 0, as type: T.Type) -> T
用于從內存中的讀取值乌叶。
lldb
通過 lldb 修改內存的值可以通過 memory write
修改:
接下來通過 lldb 把 size
變量的 width
和 height
分別改為 5 和 6 看看:
在 lldb 中也可以通過 po
指令打印變量的值:
總結
結構體對象是值類型盆偿,數據 一般情況 存放在棧空間准浴。
??: 為什么強調是 一般情況 呢事扭?因為類對象是引用類型,通常存放在堆空間乐横,如果結構體對象是類對象的成員屬性求橄,那么該結構體對象也相應地存放在了堆空間