紫安屋平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
明明我们的内存是对齐的,而按照go对空结构体的大小定义是0,应该C结构体的大小是16才对,为什么是24呢?offset 不是16吗? 16+0 = 24?
上面2个例子中,我们可以看到,同一个结构体(内容相同的)会产生不同大小的结果,一个空结构体,会额外占用8个字节的位置。这个位置就是由padding填充的。
issue,另外提及一个关于空结构体的issue。这块就不详细赘述了,空结构体为什么要分配内存的原因。
Go的整数类型一共有10个,其中计算架构相关的整数类型有两个: 有符号的整数类型 int, 无符号的整数类型 uint。在不同计算架构的计算机上,它们体现的宽度(存储某个类型的值所需要的空间)是不一样的。空间的单位可以是bit也可以是字节byte。
go的内存分配,首先是按照sizeclass划分span,然后每个span中的page又分成一个个小格子(大小相同的对象object):
span是golang内存管理的基本单位,是由一片连续的8KB(golang page的大小)的页组成的大块内存。
每个span管理指定规格(以golang 中的 page为单位)的内存块,内存池分配出不同规格的内存块就是通过span体现出来的,应用程序创建对象就是通过找到对应规格的span来存储的,下面是 mspan结构中的主要部分。
每个mspan按照它自身的属性Size Class的大小分割成若干个object,每个object可存储一个对象。
并且会使用一个位图来标记其尚未使用的object。属性Size Class决定object大小,而mspan只会分配给和object尺寸大小接近的对象,当然,对象的大小要小于object大小。
任何复杂的系统都是由很多细节优化去保证的性能,这个padding其实是在编译阶段是优化的,在runtime中没有处理过。我们在编写的过程中稍微注意一些细节,就能给我们的系统节约大量的内存(其实也节约了时间,减少了malloc 和 unmalloc)。
|