[转]http://www.cnblogs.com/wuzhenbo/archive/2012/06/05/2537465.html

1.前言

  在IBM开发社区上发现一篇叫'Data alignment: Straighten up and fly right'的文章,下面的很多内容都是来自那篇文章的。 

 内存可以看成一个byte数组,我们通过编程语言提供的工具对这个'大数组'中的每个元素进行读写,比如在C中我们可以用指针一次读写一个或者更多 个字节,这是我们一般程序员眼中的内存样子。但是从机器角度更具体的说从CPU角度看呢,CPU发出的指令是一个字节一个字节读写内存吗?答案是'否'。 CPU是按照'块(chunk)'来读写内存的,块的大小可以是2bytes, 4bytes, 8bytes, 16bytes甚至是32bytes. 这个CPU访问内存采用的块的大小,我们可以称为'内存访问粒度'。

2.程序员与CPU眼中的内存

程序员眼中的内存样子:

--------------------------------- 
| | | | | | | | | | | | | | | | | 
--------------------------------- 
0 1 2 3 4 5 6 7 8 9 A B C D E F  (地址)

CPU眼中的内存样子:(以粒度=4为例) 
--------------------------------------------- 
| | | | |      | | | | |     | | | | |      | | | | | 
--------------------------------------------- 
0 1 2 3     4 5 6 7     8 9 A B     C D E F  (地址)

注:实际上CPU是先访问cache的,当cache中的数据不存在时会以cache line大小为单位每次从memeory中读取数据到cache中,因此此处的粒度指的就是cache line的大小,cache line一般等于机器字长。

3. 访存粒度对CPU访问内存的影响

  假设这里我们需要的数据分别存储于地址0和地址1起始的连续4个字节的存储器中,我们目的是分别读取这些数据到一个4字节的寄存器中,

  • 如果'内存访问粒度'为1

CPU从地址0开始读取,需要4次访问才能将4个字节读到寄存器中; 
同样如果'内存访问粒度'为1,CPU从地址1开始读取,也需要4次访问才能将4个字节读到寄存器中;而且对于这种理想中的''内存访问粒度'为1的CPU,所有地址都是'aligned address'。

  • 如果'内存访问粒度'为2

CPU从地址0开始读取,需要2次访问才能将4个字节读到寄存器中;每次访存都能从'aligned address'起始。 
如果'内存访问粒度'为2,CPU从地址1开始读取,相当于内存中数据分布在1,2,3,4三个地址上,由于1不是'aligned address',所以这时CPU要做些其他工作,由于这四个字节分步在三个chunk上,所以CPU需要进行三次访存操作,第一次读取chunk1(即 地址0,1上两个字节,而且仅仅地址1上的数据有用),第二次读取chunk2(即地址2,3上两个字节,这两个地址上的数据都有用),最后一次读取 chunk3(即地址4,5上两个字节,而且仅仅地址4上的数据有用),最后CPU会将读取的有用的数据做merge操作,然后放到寄存器中。

  •   如果'内存访问粒度'为4

那么从地址1开始读取,需要2次访问,访问后得到的结果merge后放到寄存器中。

注:有些厂商的CPU发现你访问unaligned address,就会报错,或者打开调试器或者dump core,比如sun sparc solaris绝对不会容忍你访问unaligned address,都会以一个core结束你的程序的执行。所以一般编译器都会在编译时做相应的优化以保证程序运行时所有数据都是存储在'aligned address'上的,这就是内存对齐的由来。

4. 指定访问内存的粒度

我们可以指定按照何种粒度访问特定内存块儿:其中void *T为指向特定内存块的地址指针 
char *p = (char*)T;每次操作一个字节 
short *p = (short*)T;每次操作两个字节 
int *p = (int*)T;每次操作四个字节 
以此类推。

注:在'Data alignment: Straighten up and fly right'这篇文章中作者还得出一个结论那就是:"如果访问的地址是unaligned的,那么采用大粒度访问内存有可能比小粒度访问内存还要慢"。

5. 小结

要想提高对结构体成员的访存速度,需要做到结构体你对齐,如果要做到更高效的访存,最好是将结构体按自然对齐(自然对齐指的是地址是字长的整数倍),但是自然对齐会带来空间的损失,因此结构体对齐是空间和访问时间的折中方案。

  • 结构体一般对齐

原则A:struct或者union的成员,第一个成员在偏移0的位置,之后的每个成员的起始位置必须是当前成员大小的整数倍;

原则B:如果结构体A含有结构体成员B,那么B的起始位置必须是B中最大元素大小整数倍地址;

原则C:结构体的总大小,必须是内部最大成员的整数倍;

  • 结构体自然对齐

struct或者union的成员,第一个成员在偏移0的位置,之后的每个成员的起始地址都做到自然对齐

[转]数据对齐对CPU的影响的更多相关文章

  1. CSAPP阅读笔记-struct, union, 数据对齐-来自第三章3.9的笔记-P183-P191

    1.数据对齐 为什么要对齐:通俗点解释就是CPU对数据访问时,每次都是取固定数量的字节数,假如一次取4个字节,若有个int存在0x01-0x04,则一次就能取出,若存在0x03-0x06,则需要分两次 ...

  2. C/C++数据对齐汇总

     C/C++数据对齐汇总  这里用两句话总结数据对齐的原则: (1)对于n字节的元素(n=2,4,8,...),它的首地址能被n整除,才干获得最好的性能: (2)如果len为结构体中长度最长的变量,s ...

  3. data structure alignment(数据对齐)

    概述: 数据对齐指数据在计算机内存中排放和获取的方式.包含三个方面:数据对齐(data alignment).数据结构填充(data alignment).打包(packing) 如果数据是自然对齐的 ...

  4. 【C/C++开发】内存对齐(内存中的数据对齐)、大端模式及小端模式

    数据对齐,是指数据所在的内存地址必须是该数据长度的整数倍.DWORD数据的内存起始地址能被4除尽,WORD数据的内存起始地址能被2除尽.X86 CPU能直接访问对齐的数据,当它试图访问一个未对齐的数据 ...

  5. gcc数据对齐之: howto 2.

    原文链接:http://www.catb.org/esr/structure-packing/ 谁应阅读本文 本文探讨如何通过手工重新打包C结构体声明,来减小内存空间占用.你需要掌握基本的C语言知识, ...

  6. 谈谈C++中的数据对齐

    对于C/C++程序员来说,掌握数据对齐是很有必要的,因为只有了解了这个概念,才能知道编译器在什么时候会偷偷的塞入一些字节(padding)到我们的结构体(struct/class),也唯有这样我们才能 ...

  7. C++中数据对齐

    大体看了看数据对齐,不知道是否正确,总结如下: struct A { char name; double dHeight; int age; }; sizeof(A) = (1+7+8+4+4) =  ...

  8. STM32使用串口1配合DMA接收不定长数据,减轻CPU载荷

    STM32使用串口1配合DMA接收不定长数据,减轻CPU载荷 http://www.openedv.com/thread-63849-1-1.html 实现思路:采 用STM32F103的串口1,并配 ...

  9. gpu显存(全局内存)在使用时数据对齐的问题

    全局存储器,即普通的显存,整个网格中的随意线程都能读写全局存储器的任何位置. 存取延时为400-600 clock cycles  很easy成为性能瓶颈. 訪问显存时,读取和存储必须对齐,宽度为4B ...

随机推荐

  1. 【BZOJ2159】Crash的文明世界(第二类斯特林数,动态规划)

    [BZOJ2159]Crash的文明世界(第二类斯特林数,动态规划) 题面 BZOJ 洛谷 题解 看到\(k\)次方的式子就可以往二项式的展开上面考,但是显然这样子的复杂度会有一个\(O(k^2)\) ...

  2. C代码快速构建框架

    #include "stdio.h" typedef char int8_t; typedef short int16_t; typedef int int32_t; typede ...

  3. CF815D Karen and Cards

    CF815D Karen and Cards 固定一维c,然后(a,b)看成坐标,矩形区域求交 1.Segment tree Beats! 2.改成不合法的区域就是求并,c反向枚举,区域只增不减且完全 ...

  4. A1016. Phone Bills

    A long-distance telephone company charges its customers by the following rules: Making a long-distan ...

  5. 【LOJ#6281】数列分块5

    题目大意:维护一个有 N 个数组成的序列,支持查询区间元素和.区间元素向下取整的开方操作. 题解:由于序列中维护的数最大不超过整数的范围,而对于整数范围内的数来说,一个数在开方 5 次及以上时,结果不 ...

  6. source insight的使用方法逆天整理

    http://www.cnblogs.com/ningskyer/articles/4038501.html A. why SI: 为什么要用Source Insight呢?因为她比完整的IDE要更快 ...

  7. selenium - switch_to.window() - 多窗口切换

    在页面操作过程中有时候点击某个链接会弹出新的窗口,这时就需要主机切换到新打开的窗口上进行操作.WebDriver提供了switch_to.window()方法,可以实现在不同的窗口之间切换. 以百度首 ...

  8. springboot集成mybatis-generator时候遇到的问题

    今天在集成mybatis自动生成内容的时候,出现了几个问题,解决了一个小时才搞完,都怪之前没有好好研究研究: 1.mysql-connector-java新驱动带来的问题? 当用比较新的sql驱动的时 ...

  9. 部署高可用keepalived组件

    本文档讲解使用 keepalived 和 haproxy 实现 kube-apiserver 高可用的步骤: keepalived 提供 kube-apiserver 对外服务的 VIP: hapro ...

  10. 紧急通知:Onion勒索病毒正在大范围传播!已有大量学生中招!(转)

    在5月12日晚上20点左右,全国各地的高校学生纷纷反映,自己的电脑遭到病毒的攻击,文档被加密,壁纸遭到篡改,并且在桌面上出现窗口,强制学生支付等价300美元的比特币到攻击者账户上.我们的一位成员和其多 ...