sizeof与MemoryLayout

sizeof

在C语言中,可能会经常与sizeof打交道,用来计算数据占用内存大小。在C中sizeof即可以作用于类型也可以作用于某个实际的变量,并返回其在内存中的尺寸size_t。

在Swift 3以前,也有sizeof,不过与C中的运算符不同,它经过了一层包装,变成了一个只接受类型的方法,而接受具体值的则为另一个方法: sizeofValue

func sizeof<T>(_: T.Type) -> Int
func sizeofValue<T>(_: T) -> Int

不过sizeofValue接受的虽然是具体值,但是返回的是这个值的实际大小,而不是其内容的大小。所以与C中用sizeof拿来计算数组内容在内存中占据的尺寸不一样:

// C
char bytes[] = {1, 2, 3};
sizeof(bytes);          // 3

int bytes[] = {1, 2, 3};
sizeof(bytes);          // 12
// Swift
let bytes = [1, 2, 3]
sizeofValue(bytes)      // 8: 64位系统一个引用的长度

MemoryLayout

在Swift 3中sizeof和sizeofValue相关的被另一个新的枚举所替代,那就是MemoryLayout。

基本使用方法

let a = 10
MemoryLayout<Int>.size              // 8
MemoryLayout.size(ofValue: a)       // 8

属性方法介绍

MemoryLayout有3个非常有用的属性及3个对应的Value方法,返回值都为Int类型。

size

实例使用size(ofValue: T)

T占用连续内存的大小,单位是字节。类型的大小不包括任何动态分配或不合适的存储,当T是类类型时,MemoryLayout.size是相同的,不论T中存储属性有多少。当使用unsafe pointer为T的多个实例分配内存时,使用多个该类型的stride而不是其size,这个涉及到内存对齐的问题,详见stride。

stride

实例使用stride(ofValue: T)

当存储在连续存储器或Array中时,从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

// 值类型
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位系统中得到

参考资料