[转]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. pytesseract 使用框架

    import pytesseract import cv2 img = cv2.imread("captcha.jpg",0) try: img.shape except Attr ...

  2. A1103. Integer Factorization

    The K-P factorization of a positive integer N is to write N as the sum of the P-th power of K positi ...

  3. hinton教授的本科生课程CSC321-机器学习中的神经网的笔记

    最近一直在看仙守博友所记录的笔记 Hinton的CSC321课程(完结,待文字润色): 1.lecture1-NN的简介 2.lecture2-NN结构的主要类型的概述和感知机 3.lecture3- ...

  4. hdu 3966(树链剖分+线段树区间更新)

    传送门:Problem 3966 https://www.cnblogs.com/violet-acmer/p/9711441.html 学习资料: [1]线段树区间更新:https://blog.c ...

  5. linux下怎样查看哪些进程占用swap空间

    for i in `cd /proc;ls |grep "^[0-9]"|awk ' $0 >100'` ;do awk '/Swap:/{a=a+$2}END{print ...

  6. WCF开发实战系列四:使用Windows服务发布WCF服务

    WCF开发实战系列四:使用Windows服务发布WCF服务 (原创:灰灰虫的家http://hi.baidu.com/grayworm) 上一篇文章中我们通过编写的控制台程序或WinForm程序来为本 ...

  7. 记一次B站答题经历

    第一题部分:社区规范卷 --------- ------------ 第二题:社区规范第二部分 -------------------- 第三部分自由选择题 --------------------- ...

  8. P4994 终于结束的起点

    P4994 终于结束的起点 现在,给你一个模数 M,请你求出最小的 n > 0,使得 \(\mathrm{fib}(n) \bmod M = 0, \mathrm{fib}(n + 1) \bm ...

  9. Keepalive+nginx实现高可用负载均衡方案

    Keepalive+nginx实现高可用负载均衡方案 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.nginx做高可用工作在第几层? 上个月我发表了一篇keepalive+lv ...

  10. CodeForces - 516B Drazil and Tiles(bfs)

    https://vjudge.net/problem/CodeForces-516B 题意 在一个n*m图中放1*2或者2*1的长方形,问是否存在唯一的方法填满图中的‘.’ 分析 如果要有唯一的方案, ...