none
内存对齐字节数的麻烦! RRS feed

  • 问题

  • 在研究内存对齐的时候遇到了难题 , 或许这对于高手来说并不是什么难题,但是本人是菜鸟。呵呵!c语言中的内存对齐字节数可以通过#pragma pack(n)来设置,可是我糊涂了,因为现在cpu与内存之间传送数据的数据总线宽度是32位,也就是每次传送是四个字节的数据,那么设置一个内存对齐字节数是不是可以说cpu每次取的数据的字节数就会改变呢???如果没有改变每次取的字节数那么又会是什么呢??内存访问粒度是不是可以改变的呢??希望高手可以帮忙解决一下这个问题!!!!先谢谢了呀!!!

    2010年11月15日 3:33

答案

  • 这几天一直被一个内存对齐的问题困然着,并且到现在也没有真正的解决这个问题,但还是将自己的理解写下来,以备以后再重新来看待这个问题:

     

    内存访问粒度是不变的,也就是每次从内存中总是取四个字节的数据,如果不存在charshort类型的数据的话cpu每次都会取得想要的值,不用进行一个剔除就能够得到想要的,可是事实上是存在char类型与short类型的数据,这样cpu在取这两种类型的数据的时候就需要进行剔除了,因此在效率上就存在了一个损失,但是永远都不可能实现利益的最大化,虽然在效率上存在一定的损失,可是却节约了一部分的内存空间,字节对齐只是一个折中的方法,这种方法并不是十全十美的!!
     
     1 cpu的内存访问颗粒度是不变的,而这个颗粒度的大小,就是编
       
    译器默认的对齐。

        2
    为什么对于同一台机器,不同的变量对齐却是不同的呢?主要是
       
    一个折中(tradeoff)的问题。
       
    假设所有变量的对齐都是4,那么,当访问一个char变量时,编译器
       
    也要使该变量的地址按照4对齐,为了圆整,又要有三个字节的填充,
       
    这样做很明显内存的浪费是严重的。不同变量的对齐不同所带来的后
       
    果是:cpu在访问一个变量的时候,
       
    仍然一次读取4个字节,然后做相应的移位操作,找到所需要的地址。
       
    很明显,效率降低了。

    希望高手能够进来指正一下本人的观点!!!对于double8字节对齐,在32位机上,是由两次内存访问完成的。

        4
    使用#pragma pack(n)改变编译器的默认值的目的,是为了节约内存,
       
    但这样做的代价就是效率的降低。

        5
    凡是地址不是以4对齐的变量(在编译器默认对齐为4的机器上),比
     
    short n; char c; 以及使用#pragma pack(1),从cpu的角度看,都
     
    是不对齐的变量(unaligned address),对于有的cpu,它会采取相应
     
    的处理,能够正确访问;但对于有的cpu(lazy processor),它会抛出一
     
    个异常,而对这个异常的处理,则是os的事情。



        3

     

    • 已标记为答案 2010年11月16日 11:05
    2010年11月16日 5:32

全部回复

  • 你可以这样理解

    没有改变每次读取的字节数

    只是改变了每次读到的有效位数

    比如限定了6字节对齐

    cpu每次还是读4字节

    只是其中只有3字节有效

    然后读两次完成一个读操作

    大概就是这个意思

    这是一种牺牲效率的方法

    2010年11月15日 7:04
  • 我不知道你说的这六字节对齐是不是只是举一个例子来说明这个问题,但是很遗憾事实上是不存在六字节对齐的。如果我设置了一个字节对齐,比如:#pragma pack(1)

    struct tagMyStrcut{

    char a ;

    char b ;

    int x ;

    }

    #pragma pack()

    在这个结构体中我设置一个字节对齐,可是每次cpu总是从内存中取出四个字节的数据,那么对于第一次取字符数据a岂不是要把字符b与整型数据x的位也要取走,然后cpu再自己进行删减,得到想要的字符数据a,这样在效率上不是一种浪费吗????

     

    觉得你还是没有讲解出为什么!!!!!起码我就没有听懂!!!希望高手们能够帮忙解决一下!!!!!!

    2010年11月15日 9:42
  • 你说的对

    就是一种浪费

    不能指望计算机执行指令的时候像人一样什么都能看得见然后考虑一下再去工作

    最基本的执行方式就是一些固定的寻址方式

    当然你要是不理解就等着高手们给你详细讲解吧

    2010年11月15日 11:00
  • 难道计算机就是这样去处理数据的吗??简直不敢相信呀!!!!!呵呵!谢谢大侠了呀!同时也希望越来越多的高手能够关注一下我的帖子呀!!!!
    2010年11月15日 11:49
  • 正是由于上面的访问效率很低,所以才有内存对齐。VC++默认的对齐大小是4字节,在32位系统运行是可达到较高的运行效率。但是在64位系统中可以设置为8字节对齐。


    麻烦把正确答案设为解答。
    2010年11月16日 3:54
    版主
  • 这几天一直被一个内存对齐的问题困然着,并且到现在也没有真正的解决这个问题,但还是将自己的理解写下来,以备以后再重新来看待这个问题:

     

    内存访问粒度是不变的,也就是每次从内存中总是取四个字节的数据,如果不存在charshort类型的数据的话cpu每次都会取得想要的值,不用进行一个剔除就能够得到想要的,可是事实上是存在char类型与short类型的数据,这样cpu在取这两种类型的数据的时候就需要进行剔除了,因此在效率上就存在了一个损失,但是永远都不可能实现利益的最大化,虽然在效率上存在一定的损失,可是却节约了一部分的内存空间,字节对齐只是一个折中的方法,这种方法并不是十全十美的!!
     
     1 cpu的内存访问颗粒度是不变的,而这个颗粒度的大小,就是编
       
    译器默认的对齐。

        2
    为什么对于同一台机器,不同的变量对齐却是不同的呢?主要是
       
    一个折中(tradeoff)的问题。
       
    假设所有变量的对齐都是4,那么,当访问一个char变量时,编译器
       
    也要使该变量的地址按照4对齐,为了圆整,又要有三个字节的填充,
       
    这样做很明显内存的浪费是严重的。不同变量的对齐不同所带来的后
       
    果是:cpu在访问一个变量的时候,
       
    仍然一次读取4个字节,然后做相应的移位操作,找到所需要的地址。
       
    很明显,效率降低了。

    希望高手能够进来指正一下本人的观点!!!对于double8字节对齐,在32位机上,是由两次内存访问完成的。

        4
    使用#pragma pack(n)改变编译器的默认值的目的,是为了节约内存,
       
    但这样做的代价就是效率的降低。

        5
    凡是地址不是以4对齐的变量(在编译器默认对齐为4的机器上),比
     
    short n; char c; 以及使用#pragma pack(1),从cpu的角度看,都
     
    是不对齐的变量(unaligned address),对于有的cpu,它会采取相应
     
    的处理,能够正确访问;但对于有的cpu(lazy processor),它会抛出一
     
    个异常,而对这个异常的处理,则是os的事情。



        3

     

    • 已标记为答案 2010年11月16日 11:05
    2010年11月16日 5:32