zoukankan      html  css  js  c++  java
  • Sword 计算机内存对齐

    内存对齐理论
    
    a.数据的对齐(alignment)
    指数据的地址和由硬件条件决定的内存块大小之间的关系。一个变量的地址是它大小的倍数的时候,这就叫做自然对齐(naturally aligned)。
    例如,对于一个32bit的变量,如果它的地址是4的倍数(地址的低两位是0--备注1),那么这就是自然对齐.
    对齐的规则是由硬件引起的。一些体系的计算机在数据对齐这方面有着很严格的要求。在一些系统上,一个不对齐的数据的载入可能会引起进程的陷入。
    在另外一些系统,对不对齐的数据的访问是安全的,但却会引起性能的下降。在编写可移植的代码的时候,对齐的问题是必须避免的,所有的类型都该自然对齐。
    
    b.预对齐内存的分配
    在大多数情况下,编译器和C库透明地帮你处理对齐问题。POSIX标明了通过malloc(),calloc(),和realloc()返回的地址对于任何的C类型来说都是对齐的。
    在Linux中,这些函数返回的地址在32位系统是以8字节为边界对齐,在64位系统是以16字节为边界对齐的。有时候,对于更大的边界,程序员需要动态的对齐。
    虽然动机是多种多样的,但最常见的是直接块I/O的缓存的对齐或者其它的软件对硬件的交互,因此,POSIX 1003.1d提供一个叫做posix_memalign( )的函数
    
    c.数据对齐的性能提升
    对于现代计算机硬件来说,内存只能通过特定的对齐地址(比如按照机器字)进行访问。举个例子来说,
    比如在64位的机器上,不管我们是要读取第0个字节还是要读取第1个字节,在硬件上传输的信号都是一样的。
    因为它都会把地址0到地址7,这8个字节全部读到CPU,只是当我们是需要读取第0个字节时,丢掉后面7个字节,
    当我们是需要读取第1个字节,丢掉第1个和后面6个字节。
    假设我们要读取2个字节,这两个字节刚好落在两个机器字内时,就出现两次访问内存的情况,同时通过一些逻辑计算才能得到最终的结果。
    因此,为了更好的提升性能,我们须尽量将结构体做到机器字(或倍数)对齐,而结构体中一些频繁访问的字段也尽量安排在机器字对齐的位置。
    
    备注1:
    二进制现象解释
    对于二进制数 *****000 无论高5位怎么变化,该数一定8的倍数(对于二进制数 ******00 无论高6位怎么变化,该数一定4的倍数)
    因为是二进制, *****000 除以 2 ,结果和 0*****00 一致,相当于二进制数的每一位都降1阶,
    那么 *****000 一共可以除以3个2,即可以除以8,因此 *****000 一定是8的倍数
    /* 内存对齐 */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <string>
    
    #ifndef NGX_ALIGNMENT
    #define NGX_ALIGNMENT   sizeof(unsigned long)    /* platform word */
    #endif
    
    /*
    设计说明
        sizeof(unsigned long)
        在32位操作平台上,unsigned long 的大小是4个字节,恰巧32位平台的机器字也是4个字节
        在64位操作平台上,unsigned long 的大小是8个字节,恰巧64位平台的机器字也是8个字节
    */
    
    #define ngx_align_ptr(p, a)                                                   
        (unsigned char *) (((unsigned int) (p) + ((unsigned int) a - 1)) & ~((unsigned int) a - 1))
    
    /*
    设计说明:
        ngx_align_ptr宏定义设计详解
        (unsigned int) (p) 把地址当做整数进行操作,为了计算 整数p 加多少才是 a 的倍数
    
        (unsigned int) (p) + ((unsigned int) a - 1 将 整数p 向上扩充,因为是内存对齐,地址只能向后跑。向前跑就可能内存越界
        假设a是8,(((unsigned int) (p) + ((unsigned int) a - 1)) & ~((unsigned int) a - 1)) 只会影响 低3位,如果 整数p 在低位上有值,
        那么 整数p 就会比原来小,而 整数p + a - 1 整数p的低3位上全部加1,如果 整数p 低3位上有值,肯定会产生进位,
        这样可以确保操作后的 整数p 绝对比 原来的整数p 大
    
        (((unsigned int) (p) + ((unsigned int) a - 1)) & ~((unsigned int) a - 1)) 假设a是8,该操作就会将 整数p 后3位变成0
    */
    
    int main()
    {
        //示例用法
        void * p = (void *)0x2379b1;
        //进行内存对齐操作
        p = ngx_align_ptr(p, NGX_ALIGNMENT);
        return 0;
    }
    posix_memalign
    
    函数原型
    int posix_memalign(void **memptr, size_t alignment, size_t size);
    
    函数说明
    调用posix_memalign( )成功时会返回size字节的动态内存,并且这块内存的地址是alignment的倍数。参数alignment必须是2的幂,
    还是void指针的大小的倍数。返回的内存块的地址放在了memptr里面,函数返回值是0. 返回值 调用失败时,没有内存会被分配,memptr的值没有被定义,返回如下错误码之一: EINVAL 参数不是2的幂,或者不是void指针的倍数。 ENOMEM 没有足够的内存去满足函数的请求。 注意 posix_memalign函数,errno不会被设置,只能通过返回值得到。 由posix_memalign( )获得的内存通过free( )释放
  • 相关阅读:
    Solution: Win 10 和 Ubuntu 16.04 LTS双系统, Win 10 不能从grub启动
    在Ubuntu上如何往fcitx里添加输入法
    LaTeX 笔记---Q&A
    Hong Kong Regional Online Preliminary 2016 C. Classrooms
    Codeforces 711E ZS and The Birthday Paradox
    poj 2342 anniversary party
    poj 1088 滑雪
    poj 2479 maximum sum
    poj 2481 cows
    poj 2352 stars
  • 原文地址:https://www.cnblogs.com/zhanggaofeng/p/11703591.html
Copyright © 2011-2022 走看看