为什么某些类型(例如Float80)的内存对齐大于字大小?

时间:2015-03-06 11:56:39

标签: swift memory-alignment

为了使它具体化,我只想知道为什么在我的64位mac上,Swift编译器说某些类型如Float80的对齐是16。 要检查类型的内存对齐要求,我使用alignof函数。

sizeof(Float80) // ~> 16 bytes, it only needs 10 bytes, but because of hardware design decisions it has to be a power of 2
strideof(Float80) // ~> 16 bytes, clear because it is exact on a power of 2, struct types with Float80 in it, can be bigger
alignof(Float80) // ~> 16 bytes, why not 8 bytes, like String ?

我理解类型的内存对齐小于或等于单词的大小是有益的。

sizeof(String) // ~> 24 bytes, clear because 24 is multiple of 8
strideof(String) // ~> 24 bytes, clear because 24 is multiple of 8
alignof(String) // ~> 8 bytes, clear because something greater or equal to 8 bytes should align to 8 bytes

许多具有更大内存大小的类型(如String(大小为24))的内存对齐要求为8个字节。我希望这是我正在使用的CPU / RAM总线的大小,因为我有一个64位的mac和os。 我检查了类型的大小,没有使用sizeof函数的最后一个填充,并且使用strideof函数添加填充到结尾(strideof在结构数组中更有用,Swift然后将字节添加到末尾以达到对齐要求的下一个倍数。)

据我所知,填充对于小于或等于8字节大小的类型是必要的。

但我不明白为什么在我的64位mac上有一个大于8字节的内存对齐要求是有利的。

Float80的值需要80位,即10个字节,有6个填充字节。

这是一张图片,使其更加清晰,我的意思。 Float80允许绿色位置,红色位置不允许。 此图片中的内存为8字节块。

byte and word Float80 memory alignment in Swift

2 个答案:

答案 0 :(得分:6)

所有“原始数据类型”(该术语可能是错误的,我的意思是 处理器使用的数据类型具有“自然边界”, 并且编译器会相应地将它们对齐在内存中。对齐 取决于处理器(例如x86或ARM)和编程环境(例如32位与64位)。 某些处理器允许未对齐的数据(可能以较低的速度), 有些人不允许这样做。

对于64位Intel架构,要求列于 Data Alignment when Migrating to 64-Bit Intel® Architecture

  

然而,64位环境对数据项提出了更严格的要求。未对齐的对象会导致程序异常   [...]

     
      
  • 在任意地址对齐8位数据
  •   
  • 将16位数据对齐以包含在对齐的四字节字中
  •   
  • 对齐32位数据,使其基址为四的倍数
  •   
  • 对齐64位数据,使其基址为8的倍数
  •   
  • 对齐80位数据,使其基址为16的倍数
  •   
  • 对齐128位数据,使其基址为16的倍数
  •   

因此,对齐不一定等于“字大小”,它可以是 少或多或少。 Float80对应于“扩展精度” x86处理器的浮点类型,它的对齐方式是 需要是16个字节。

C struct等复合类型在内存中布局 每个成员都在其自然边界上(并插入填充 在必要时间。结构的对齐方式 本身是每个成员的最大对齐方式。

Swift Struct的内存布局没有正式记录(据我所知)但它可能与C struct类似。 这是一个简单的例子:

struct AStruct {
    var a = Int32(0)
    var b = Int8(0)
    var c = Int16(0)
    var d = Int8(0)
}
println(sizeof(AStruct))     // 9
println(alignof(AStruct))    // 4
println(strideof(AStruct))   // 12

内存布局(可能)是(* =填充):

aaaab*ccd

此处对齐为4,因为这是Int32所需的对齐方式。结构占用9个字节,但“步幅”为12: 这保证了在结构数组中所有元素都满足 相同的路线。

(请注意,Swift strideOf()对应于C sizeof()函数,https://devforums.apple.com/message/1086107#1086107中对此进行了解释。)

Swift字符串的声明显示为

struct String {
    init()
}

但我们凡人都看不到实际成员。 在调试器中,它看起来像这样:

enter image description here

表示其成员是指针, 无符号字和另一个指针。所有这些类型都有一个大小和 在64位上对齐8个字节。这可以解释大小(24字节) 和struct Swift的对齐(8个字节)。

答案 1 :(得分:3)

在Martin R的链接的帮助下,暗示这是处理器设计的决定。我找到了readon为什么。

缓存行。

缓存行是处理器的一个非常小的内存,在我的Intel Mac 64位上它是128位(16字节)。

如问题图片所示,我知道点线和粗线之间存在差异。粗线位于处理器的高速缓存行之间。如果你可以用更多的内存成本做得更好,你不想加载2个缓存行。因此,如果处理器只允许,那么大小为8字节(或更大)的类型在高速缓存行的开头(16的每个倍数)上对齐。对于与高速缓存行一样大的类型,将不会有两个高速缓存行读取(在我的情况下,字大小加倍,16个字节)。正如您在图片中看到的那样,只有红色块穿过粗线(因此每个设计不允许使用它们)。

请参阅附带的链接以获取更多信息。

Cache effects