这个Swift结构体实际上使用了多少存储空间?

3
假设我有以下结构体 -
struct MyStruct {
    var value1: UInt16
    var value2: UInt16
}

我在代码中的某个地方使用了这个结构体,如下所示 -

var s = MyStruct(value1: UInt16(0), value2: UInt16(0))

我知道这个结构体将需要32位存储来存储两个16位整数 -

我不确定的是,Swift是否会为每个值分配两个额外的64位指针,以及一个64位指针用于变量s

这是否意味着以上代码的总存储需求将导致以下结果?

MyStruct.value1     - 16-bits
MyStruct.value1 ptr - 64-bits
MyStruct.value2     - 16-bits
MyStruct.value2 ptr - 64-bits
s ptr               - 64-bits
–––––––––––––––––––––––––––––
Total               - 224-bits

有人能否请解释一下吗?


1
我的程序有非常严格的内存要求,我需要尽可能地优化存储。指针存储是一个已知的内存浪费杀手,我正在努力理解如何最好地优化我的代码。 - Randy
非常正确,但我真正处理的只是像上面示例中那样的原始类型。除了 Array 和 Dictionary 背后的自动增长行为之外,Swift 是否引入了其他类型的额外内存开销,我应该注意到吗? - Randy
3个回答

1

MyStruct 是 4 字节,因为 sizeof(UInt16) 是 2 字节。要测试任何给定类型的大小,请使用 sizeofsizeof 返回内存大小,以字节为单位。

let size = sizeof(MyStruct) //4

如果您想获取给定实例的大小,可以使用 sizeOfValue
var s = MyStruct(value1: UInt16(0), value2: UInt16(0))
let sSize = sizeofValue(s) //4

我相信指针的大小取决于体系结构/编译器,大多数计算机和许多新手机是64位,但旧设备可能是32位。
我认为没有办法真正获得指向MyStruct.value1的指针,如果我错了,请纠正我(我正在尝试&s.value1)。
指针
在Swift中,结构体是在堆栈上创建并传递的,这就是它们具有值语义而不是引用语义的原因。
当函数中创建结构体时,它存储在堆栈上,因此在函数结束时其内存被释放。它的引用只是从堆栈指针或帧指针偏移的。

嗨,Kevin,你关于架构是正确的。我想要理解的是Swift何时会内部创建指针,何时不会。 - Randy
哦,我知道你在想什么。结构体被分配在栈上,而类被分配在堆上。你(大多数情况下)使用指针来提供堆中的地址。结构体通常不需要通过引用/指针传递。当它们被传入函数时,它们的值会被复制。这有帮助吗? - Kevin
谢谢,Kevin。是的,我知道堆栈语义。我相对确定Swift需要保留对s的指针,以便稍后可以从内存中调用该值,即使该值存储在堆栈上。 - Randy
在函数结束时,存储结构体的堆栈帧已经消失。所有这些内存都不需要保留。 - Kevin
那非常有道理。谢谢! - Randy

1

它将在堆栈上占用四个字节。


嗨Atamiri,能否请您详细说明一下?变量" s "需要任何指针存储吗? - Randy

1

只需在XCode Playground中尝试一下:

Sizeof MyStruct

答案是4个字节。

没有指针。UInts本身就是结构体,因此它们不使用引用(与基于类的对象不同)。因此,任何类型为MyStruct的变量所使用的总空间为4个字节。 - LIProf
请原谅我的无知,但当需要将值传递给函数时,该值如何从内存中调用?地址是否暂时存储在寄存器中? - Randy
我需要了解更多有关编译器的信息才能确定,但如果它与大多数C / C ++编译器类似,它将计算对象相对于某个基址的偏移量。 如果变量在函数内声明,则基址将是运行时堆栈帧的起始地址。 在运行时,将从寄存器中获取堆栈框架起始地址并加上偏移量,以获得对象的起始地址。 - LIProf
再次感谢您,LI教授。这真的帮助我澄清了事情。 - Randy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接