在C
语言中,可能会经常与sizeof
打交道,用来计算数据占用内存大小。在C
中sizeof
即可以作用于类型也可以作用于某个实际的变量,并返回其在内存中的尺寸size_t
。
在Swift 3
以前,也有sizeof
,不过与C
中的运算符不同,它经过了一层包装,变成了一个只接受类型的方法,而接受具体值的则为另一个方法: sizeofValue
1 2 | func <T>(_: T.Type) -> Int func sizeofValue<T>(_: T) -> Int |
不过sizeofValue
接受的虽然是具体值,但是返回的是这个值的实际大小,而不是其内容的大小。所以与C
中用sizeof
拿来计算数组内容在内存中占据的尺寸不一样:
1 2 3 4 5 6 | char bytes[] = {1, 2, 3}; sizeof(bytes); // 3 int bytes[] = {1, 2, 3}; sizeof(bytes); // 12 |
1 2 3 | // Swift let bytes = [1, 2, 3] sizeofValue(bytes) // 8: 64位系统一个引用的长度 |
MemoryLayout
在Swift 3
中sizeof
和sizeofValue
相关的被另一个新的枚举所替代,那就是MemoryLayout
。
基本使用方法
1 2 3 | let a = 10 MemoryLayout<Int>.size // 8 MemoryLayout.size(ofValue: a) // 8 |
属性方法介绍
MemoryLayout
有3个非常有用的属性及3个对应的Value
方法,返回值都为Int
类型。
size
实例使用size(ofValue: T)
T
占用连续内存的大小,单位是字节。类型的大小不包括任何动态分配或不合适的存储,当T
是类类型时,MemoryLayout<T>.size
是相同的,不论T
中存储属性有多少。当使用unsafe pointer
为T
的多个实例分配内存时,使用多个该类型的stride
而不是其size
,这个涉及到内存对齐的问题,详见stride。
stride
实例使用stride(ofValue: T)
当存储在连续存储器或Array<T>
中时,从T
的任意一个实例开始到下一个实例开始所占用的连续内存字节大小。
示例:
这是一个数组,里面有四个T
类型元素,每个T
元素的大小为size
个字节,但是因为内存对齐的限制,每个T
类型元素实际消耗的内存空间为stride
个字节,stride - size
个字节则为每个元素因为内存对齐而浪费的内存空间。
alignment
实例使用alignment(ofValue: T)
T
的默认内存对齐方式,单位为字节。许多计算机系统对基本数据类型的合法地址做出了一些限制,要求某种数据类型对象的地址必须是某个值K(通常是 2、4或者8)的倍数。这种对齐限制简化了形成处理器和内存系统之间接口的硬件设计。对齐原则是任何K字节的基本对象的地址必须是K的倍数。
MemoryLayout.alignment
就代表着数据类型T
的内存对齐原则。而且在64位系统下,最大的内存对齐原则是8字节。
基本数据类型的MemoryLayout
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | // 值类型 MemoryLayout<Int>.size // 8 MemoryLayout<Int>.stride // 8 MemoryLayout<Int>.alignment // 8 MemoryLayout<String>.size // 24 MemoryLayout<String>.stride // 24 MemoryLayout<String>.alignment // 8 // 引用类型 T MemoryLayout<T>.size // 8 MemoryLayout<T>.stride // 8 MemoryLayout<T>.alignment // 8 // 指针类型 MemoryLayout<unsafeMutablePointer<T>>.size // 8 MemoryLayout<unsafeMutablePointer<T>>.stride // 8 MemoryLayout<unsafeMutablePointer<T>>.alignment // 8 MemoryLayout<unsafeMutableBufferPointer<T>>.size // 16 MemoryLayout<unsafeMutableBufferPointer<T>>.stride // 16 MemoryLayout<unsafeMutableBufferPointer<T>>.alignment // 16 |
注意
以上所有都在64位系统中得到