data structure alignment(数据对齐)
概述:
数据对齐指数据在计算机内存中排放和获取的方式。包含三个方面:数据对齐(data alignment)、数据结构填充(data alignment)、打包(packing)
如果数据是自然对齐的话,CPU读写会更高效。自然对齐指数据地址是数据大小的倍数。为保证自然对齐,可能会在结构的开头或结尾进行一些填充
定义:
内存地址对齐:一个内存地址a被称为n-byte对齐,如果a是n的倍数,其中n是2的幂。因此n对齐的地址的低log2(n)位是0
n-bit对齐 = n/8-byte对齐
内存读取对齐:读取n bytes的数据,且数据地址是n-byte对齐的
内存指针对齐:一个指向基本数据类型的指针是n-byte对齐的,如果指针指向的地址只能是n-byte对齐的;一个指向数组或结构体的指针是n-byte对齐的,如果每个基本数据元素都是n-byte对齐的
以上定义假设基本数据类型的大小都是2的幂,否则是否对齐要依情况而定
问题:
内存读取以字为单位,如果字的大小大于最大的基本数据类型,那么对齐内存的读取总是读取单一的字
如果是非对齐内存的读取,即数据的高地址和低地址不在同一个字中,那么对这个数据的读取就要分多次进行,多次读取并把它们整合起来需要更加复杂的电路。而且如果数据在不同的页上,处理器还要在执行指令之前确认这些页是否都在当前内存中,否则还要在执行指令的时候执行TLB缺失或页错误
单一字的读取是原子的,其他的设备将等待当前设备读取该字之后才可以获取它。但是如果是非对齐的数据,在当前设备读取一个字之后,其他的设备可能会改变这个数据,然后当前设备再读取剩下的字,导致脏读问题
数据结构填充:
一个数据结构中的数据成员可能会有不同的对齐要求,所以为保证成员有合适的对齐规则,解释器会填充未命名的数据成员,此外还可能会为数据结构作为一个整体的对齐规则填充未命名成员。这样就能保证无论是所有的数据成员还是作为一个整体都有合适的对齐规则。
在一个成员后面的成员需要更大的对齐方式或者是结构结束的时候才会需要填充,所以改变成员的顺序可以减少填充需要的空间。但是成员按递减的对齐方式排列并不一定保证最小的填充需求。
C和C++不允许编译器重新排列结构的成员,某些语言可能允许。但是C和C++编译器允许指定编译器的对齐等级。如"pack(2)"意味着2-byte对齐,所以填充的成员至多一个字节
一般填充用于节省空间,但也可以用于为一个传输协议格式化数据结构
分配内存时对齐cache线:
对齐cache线的分配内存将会使效率更高。如果数组分为多个线程处理,但是子数组没有对齐cache线,那么会使性能降低。
对齐分配举例:
#include <stdlib.h>
double *foo(void) {
double *var;//create array of size 10
int ok;
ok = posix_memalign((void**)&var, 64, 10*sizeof(double));
if(ok != 0)
return NULL;
return var;
}
//来自 <https://en.wikipedia.org/wiki/Data_structure_alignment>
硬件的对齐需求:
对齐还可以用于提升硬件水平地址转换的效率(虚拟地址转化为物理地址)
举例:假设有32位操作系统采取4KB大小的页。那么一个页并不是任意的一块区域,而是4KB对齐的内存区域。这会简化硬件把虚拟地址转化为物理地址的代价,硬件上直接把高位地址替换掉,而不必进行更多的计算。
比如TLB把虚拟地址0x2cfc7000映射为物理地址0x12345000,这两个地址都是4KB对齐的,所以当硬件想要把0x2cfc7abc的虚拟地址转化为物理地址的时候只需要把高20位替换为0x12345
一个大小为的数据块总有
大小的一块是可以进行
对齐的。所以可以这样申请一块对齐的内存:
// Example: get a 12-bit aligned 4 KBytes buffer with malloc()
// unaligned pointer to large area
void *up = malloc((1 << 13) - 1);
// well-aligned pointer to 4 KBytes
void *ap = aligntonext(up, 12);
//来自 <https://en.wikipedia.org/wiki/Data_structure_alignment>
C运行时栈的对齐实验:
运行环境:gcc version 6.3.0 (MinGW.org GCC-6.3.0-1) on Windows10
在命令行编译运行
代码:
#include <stdio.h>
int func(void){
int c;
printf("stack top in func \t%p\n", &c);
return 1;
}
void main(void) {
int arr[0];
int i;
printf("stack top before func \t%p\n", &i);
func();
return;
}
结果:
stack top before func 0061FF2C
stack top in func 0061FEFC
调用函数的花费栈空间位48字节。然后改变arr的大小为1:
stack top before func 0061FF28
stack top in func 0061FEFC
然后调用函数花费的栈空间就是44字节。当arr的大小时3的时候调用函数使用的栈空间不再减小,而新的栈花费为52字节
原因:
这是因为运行时栈也是需要对齐的,而且GNU的默认对齐方式是16字节。我在编译时加上选项"-mpreferred-stack-boundary=2"将对齐方式设置为4字节(),之后我改变arr的大小,调用函数使用的栈空间只会平移而不会改变大小
在StackOverflow提问的回答:
很重要的一点是,在同一个函数中为声明的变量分配栈空间的顺序不一定按照声明的顺序分配,所以不能在函数调用之后声明另一个变量来探测栈顶
参考:
https://en.wikipedia.org/wiki/Data_structure_alignment
data structure alignment(数据对齐)的更多相关文章
- 对象内存 (扩展 Data Structure Alignment)
对于一个class object来说,我们需要多少内存才能表现出来,大致分为3类,这里在前面文章有内存图 (1)非静态数据成员的综合大小,这也符合了c++对象模型的结构 (2)填充字节,就是我们所说的 ...
- Data structure alignment by binary operation
在寫C的過程中,我們會很自然地以為,我連續宣告一堆大小不一的char array. 經過Complier之後這些char array未必是連續擺放.至於為什麼就要談到我們今天的主角了alignment ...
- 两数之和-数据结构设计 · Two Sum - Data structure design
[抄题]: 设计b并实现一个 TwoSum 类.他需要支持以下操作:add 和 find.add -把这个数添加到内部的数据结构.find -是否存在任意一对数字之和等于这个值 [思维问题]: 不知道 ...
- [LeetCode] 211. Add and Search Word - Data structure design 添加和查找单词-数据结构设计
Design a data structure that supports the following two operations: void addWord(word) bool search(w ...
- 【LeetCode】211. Add and Search Word - Data structure design 添加与搜索单词 - 数据结构设计
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 公众号:负雪明烛 本文关键词:Leetcode, 力扣,211,搜索单词,前缀树,字典树 ...
- [LeetCode] Add and Search Word - Data structure design 添加和查找单词-数据结构设计
Design a data structure that supports the following two operations: void addWord(word) bool search(w ...
- [LeetCode] Two Sum III - Data structure design 两数之和之三 - 数据结构设计
Design and implement a TwoSum class. It should support the following operations:add and find. add - ...
- LeetCode 170. Two Sum III - Data structure design (两数之和之三 - 数据结构设计)$
Design and implement a TwoSum class. It should support the following operations: add and find. add - ...
- [Swift]LeetCode170.两数之和III - 数据结构设计 $ Two Sum III - Data structure design
Design and implement a TwoSum class. It should support the following operations:add and find. add - ...
随机推荐
- mysql对事务的支持
起因:因为只是需要编写一个接口,无需使用框架,但是又要求对数据库的操作支持事务,所以直接使用mysql自带的事务进行处理 mysql自带对事务的支持,但是他默认是关闭的,需要我们手动打开,打开mysq ...
- NOI 2018 你的名字 (后缀自动机+线段树合并)
题目大意:略 令$ION2017=S,ION2018=T$ 对$S$建$SAM$,每次都把$T$放进去跑,求出结尾是i的前缀串,能匹配上$S$的最长后缀长度为$f_{i}$ 由于$T$必须在$[l,r ...
- BZOJ 1396 识别子串 (后缀自动机+线段树)
题目大意: 给你一个字符串S,求关于每个位置x的识别串T的最短长度,T必须满足覆盖x,且T在S中仅出现一次 神题 以节点x为结尾的识别串,必须满足它在$parent$树的子树中只有一个$endpos$ ...
- python异常处理,多线程,多进程
什么是异常? 异常即是一个事件,该事件会在程序执行过程中发生,影响了程序的正常执行. 一般情况下,在Python无法正常处理程序时就会发生一个异常. 异常是Python对象,表示一个错误. 当Pyth ...
- 标题:u-boot 移植步骤详解
1 U-Boot简介U-Boot,全称Universal Boot Loader,是遵循GPL条款的开放源码项目.从FADSROM.8xxROM.PPCBOOT逐步发展演化而来.其源码目录.编译形式与 ...
- 样本方差的无偏估计与(n-1)的由来
一.无偏估计 所谓总体参数估计量的无偏性指的是,基于不同的样本,使用该估计量可算出多个估计值,但它们的平均值等于被估参数的真值. 在某些场合下,无偏性的要求是有实际意义的.例如,假设在某厂商与某销售商 ...
- LaTeX 表格指定宽度并居中
本系列文章由 @YhL_Leo 出品,转载请注明出处. 文章链接: http://blog.csdn.net/yhl_leo/article/details/50532269 在绘制表格的时候,对于特 ...
- [cocos2dx笔记013]一个使用CCRenderTexture创建动态纹理显示数字的类
用CCLabelTTF显示的数字不好看.于是就想到用图片来代理.眼下网上的实现都是把每一个数字做一个CCSprite组合的方式. 可是我想.动态生成纹理的方式.没有就仅仅好自己手动写一个. 头文件 # ...
- lambda的函数式接口
函数式接口就是只包含一个抽象方法的接口A(不包括默认抽象方法,但包括继承来的方法):这个接口用来作为一个可变作用的方法B的参数.函数式接口的抽象方法的参数类型和返回值就是一套签名,这个签名叫做函数描述 ...
- Woody的Python学习笔记2
Python多行语句 Python语句中一般以新行作为语句的结束符.但我们能够使用斜杠(\)将一行的语句分为多行显示,例如以下所看到的: total = item_one+\ item_two + \ ...