• 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( )释放
  • 相关阅读:
    Pwn-level3
    【mysql】 mysql忘记密码
    【Linux】linux磁盘管理
    【Linux】Linux系统LVM管理及Raid
    【Git】git撤销与回滚
    【linux】Linux系统SELinux简介
    【Linux】Linux中的网络命令
    【Linux】linux中文本操作利器grep,awk,sed
    【Linux】linux正则表达式及通配符
    【Mysql】mysql数据备份
  • 原文地址:https://www.cnblogs.com/zhanggaofeng/p/11703591.html
Copyright © 2020-2023  润新知