zoukankan      html  css  js  c++  java
  • c++内存对齐

    内存对齐的原因

    为了提高程序的性能,数据结构(尤其是栈)应该尽可能地在自然边界上对齐。因为为了访问未对齐的内存,CPU需要作两次内存访问。然而,对齐的内存访问仅需要一次访问。

    内存对齐的规则

    1、数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照 #pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。

    2、结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较大的那个进行。

    普通结构体

    一般c++编译器默认的内存的对齐值为8个字节。对于下面的TEST结构体。因为其第一个字段为char所占字节为1,而第二个字段为int在32位系统中占4个字节,默认对齐值为8,宏观对齐值为4。因为char cNum1的字节大小为1地址为0x00AFFC50,所以其对齐值为1。int cNum2占4个字节所以对齐值为4,所以其首地址要能被4整除所以0x00AFFC51-0x00AFFC53用0xCC填充用来对齐。结构体总体大小为实际宏观对齐值与默认对齐值中较大的那个,所以sizeof(TEST)的大小为0x8.

    结构体中含有数组

    如果结构体宏含有数组则用数组的类型参与对齐值的计算,不能按数组的总大小参与对齐值的运算。

    结构体中含有结构体

    如果结构体中含有结构体则应用结构体的对齐值参与对齐值的运算,而不能用结构体的大小参与对齐值的运算。

    内存没对齐进行错位访问数据

    DWORD * pDword = new DWORD[10]();
    pDword = (DWORD*)((BYTE*)pDword + 1);
    
    DWORD a = *pDword;				//进行了错位访问数据
    

    x86CPU的EFLAGS寄存器的AC标志位是对齐检查标志位,其默认是为0的,这时cpu进行错位访问数据(访问未对齐的数据)时需要CPU多执行一些操作,比访问对齐的数据效率要低但是并不会产生异常。如果AC标志位为1则一旦CPU进行错位访问时就会产生一个异常,但是对于x86-64处理器来说,CPU会默认处理这种错误。但是对于IA-64处理器来说其CPU不能处理这种错误会将这种错误传递给操作系统,Windows操作系统会产生EXCEPTION_DATATYPE_MISALINGNMENT异常。

    处理IA-64处理器上错位访问数据

    让操作系统处理

    SetErrorMode(SEM_NOALIGNMENTFAULTEXCEPT);
    

    通过调用在进程中调用SetErrorMode并传入参数SEM_NOALIGNMENTFAULTEXCEPT来让操作系统修正此进程中所有的错位数据的访问,一旦改变该标志就无法在进程生命周期再次改变它,且这样进程可能会遇到严重的性能下降。

    让编译器处理

    Microsoft Visual C/C++编译器利用__unaligned关键字修饰可能会错位访问数据的指针,从而生成额外的指令来访问数据。

    DWORD * pDword = new DWORD[10]();
    pDword = (DWORD*)((BYTE*)pDword + 1);
    
    DWORD a = *(__unaligned DWORD *)pDword;				//使用__unaligned关键字访问数据
    

    参考《Windows核心编程》

  • 相关阅读:
    bzoj 1030 [JSOI2007]文本生成器
    Swift 学习笔记 (闭包)
    Swift 学习笔记 (函数)
    HTML 学习笔记 JQueryUI(Interactions,Widgets)
    HTML 学习笔记 JQuery(表单,表格 操作)
    HTML 学习笔记 JQuery(animation)
    HTML 学习笔记 JQuery(盒子操作)
    HTML 学习笔记 JQuery(事件)
    HTML 学习笔记 JQuery(DOM 操作3)
    HTML 学习笔记 JQuery(DOM 操作2)
  • 原文地址:https://www.cnblogs.com/revercc/p/13810678.html
Copyright © 2011-2022 走看看