zoukankan      html  css  js  c++  java
  • CLR笔记 三 类型中字段布局

    CLR如何控制类型中的字段布局

    为提高性能,在未指定类型或者结构体的字段的任何排列方式时,CLR会按照自己认为最合适的方式进行重新排列,即内存对齐。

    如何指定类或者结构体内字段的排列方式

    在类型或者结构体内添加特性System.Runtime.InteropServices.StructLayoutAttribute;

    传递枚举参数LayoutKind

    具体参数说明(微软代码有介绍):

     1     //
     2     // 摘要:
     3     //     当将对象导出到非托管代码时,控制该对象的布局。
     4     [ComVisible(true)]
     5     public enum LayoutKind
     6     {
     7         //
     8         // 摘要:
     9         //     对象的成员顺序依次布局,它们出现导出到非托管内存时的顺序。 成员进行布局中指定的封装根据System.Runtime.InteropServices.StructLayoutAttribute.Pack,和可以是不连续。
    10         Sequential = 0,
    11         //
    12         // 摘要:
    13         //     非托管内存中的每个成员的对象的精确位置显式控制,受约束的设置System.Runtime.InteropServices.StructLayoutAttribute.Pack字段。
    14         //     每个成员必须使用System.Runtime.InteropServices.FieldOffsetAttribute指示该字段的类型中的位置。
    15         Explicit = 2,
    16         //
    17         // 摘要:
    18         //     非托管内存中某个对象的成员,则运行时会自动选择适当的布局。 无法在托管代码之外公开使用此枚举成员定义的对象。 尝试这样做将引发异常。
    19         Auto = 3
    20     }
    21 }
    View Code

    需要注意的是Microsof C#编译器总是默认的为引用类型选择Layoutkind.Auto,为值类型选择LayoutKind.Sequential(也许其他的C#编译器不是这么做的)。

    LayoutKind.Sequential一般用于和非托管代码进行交互,若不与非托管代码进行交互可以显式指定为Auto可以提高性能。

    LayoutKind.Explicit:精确指定字段偏移量(相对于实例的起始位置),使用FieldOffSet特性指定。

    Tips:

    对于LayoutKind.Explicit:

    1.一般用于C/C++具有union的类,该类的数据成员在内存中的存储互相重叠,每个数据成员都冲相同的内存地址开始,分配给union的存储区数量是它包含最大数据成员所需的内存数,同一时刻只有一个成员可以被赋值。

    2.引用类型和值类型互相重叠是不合法的,多个引用类型互相重叠时,该类型无法验证,多个值类型互相重叠是合法的,但所有重叠字节都能通过公共字段访问,方能够验证;

    实际应用

    通过win32函数获取当前操作系统的逻辑CPU核心数:GetSystemInfo或者GetNativeSystemInfo(微软API:https://msdn.microsoft.com/en-us/library/ms724381(v=VS.85).aspx),其输出类型结构体为:SYSTEM_INFO:

    该结构体定义:

    typedef struct _SYSTEM_INFO {
      union {
        DWORD  dwOemId;
        struct {
          WORD wProcessorArchitecture;
          WORD wReserved;
        };
      };
      DWORD     dwPageSize;
      LPVOID    lpMinimumApplicationAddress;
      LPVOID    lpMaximumApplicationAddress;
      DWORD_PTR dwActiveProcessorMask;
      DWORD     dwNumberOfProcessors;
      DWORD     dwProcessorType;
      DWORD     dwAllocationGranularity;
      WORD      wProcessorLevel;
      WORD      wProcessorRevision;
    } SYSTEM_INFO;

    其中含有一个匿名联合体体,该联体内字段dwOemid与匿名联合体中的匿名结构体起始地址一样,由于dwOemid是DWORD类,而匿名结构体内的两个字段都为WORD类型,DWORD类型是4个字节类型,WORD是双字节,所以dwOemId的低16位与wProcessArchitecture内存共用,dwOemId的高16位与wReserved内存共用;所以在C#代码中可以这样声明SYSTEM_INFO结构体:

     1         [StructLayout(LayoutKind.Sequential)]
     2         public struct System_Info
     3         {
     4             /// <summary>
     5             /// 已过时为保持兼容性留下的结构体
     6             /// </summary>
     7             [Obsolete("已过时为保持兼容性留下的结构体")]
     8             public OemId oemId;
     9             /// <summary>
    10             /// 
    11             /// </summary>
    12             public UInt32 dwPageSize;
    13             /// <summary>
    14             /// 应用程序或者DLL最小地址指针
    15             /// </summary>
    16             public IntPtr lpMinimumApplicationAddress;
    17             /// <summary>
    18             /// 应用程序或者DLL最大地址指针
    19             /// </summary>
    20             public IntPtr lpMaximumApplicationAddress;
    21             /// <summary>
    22             /// 系统内处理器配置的标记
    23             /// </summary>
    24             public IntPtr dwActiveProcessorMask;
    25             /// <summary>
    26             /// 处理器数量
    27             /// </summary>
    28             public UInt32 dwNumberOfProcessors;
    29             /// <summary>
    30             /// 处理器类型
    31             /// </summary>
    32             [Obsolete("已过时,为兼容性保留,")]
    33             public UInt32 dwProcessorType;
    34             /// <summary>
    35             /// 虚拟内存分配的颗粒度
    36             /// </summary>
    37             public UInt32 dwAllocationGranularity;
    38             /// <summary>
    39             /// 架构相关的处理器等级
    40             /// </summary>
    41             public UInt16 wProcessorLevel;
    42             /// <summary>
    43             /// 处理器修订号
    44             /// </summary>
    45             public UInt16 wProcessorRevision;
    46         }
    47 
    48         /// <summary>
    49         /// 已过时为保持兼容性留下的结构体
    50         /// </summary>
    51         [StructLayout(LayoutKind.Explicit)]
    52         public struct OemId
    53         {
    54             [FieldOffset(0)]
    55             UInt32 dwOemId;
    56             /// <summary>
    57             /// 安装系统处理器架构
    58             /// </summary>
    59             [FieldOffset(0)]
    60             UInt16 wProcessArchitecture;
    61             /// <summary>
    62             /// 将来预留字段
    63             /// </summary>
    64             [FieldOffset(16)]
    65             UInt16 wReserved;
    66         }
    67 
    68         public enum ProcessArchitecture
    69         {
    70             /// <summary>
    71             /// x64 AMD or intel
    72             /// </summary>
    73             PROCESSOR_ARCHITECTURE_AMD64 = 9,
    74             /// <summary>
    75             /// ARM
    76             /// </summary>
    77             PROCESSOR_ARCHITECTURE_ARM = 5,
    78             /// <summary>
    79             /// ARM64
    80             /// </summary>
    81             PROCESSOR_ARCHITECTURE_ARM64 = 12,
    82             PROCESSOR_ARCHITECTURE_IA64 = 6,
    83             PROCESSOR_ARCHITECTURE_INTEL = 0,
    84             PROCESSOR_ARCHITECTURE_UNKNOWN = 0xffff,
    85         }
    View Code

    然后调用下看看结果。

    问题

    1.LayoutKind.Auto为什么可以提高性能?

    https://www.cnblogs.com/kex1n/archive/2009/06/16/2286527.html

    2.什么是类型验证?如何进行类型验证?

    参考:

    1.CLR Via C#;2.

  • 相关阅读:
    [国家集训队]拉拉队排练 Manancher_前缀和_快速幂
    高手过愚人节 Manancher模板题_双倍经验
    [模板]manacher算法
    [POI2011]MET-Meteors 整体二分_树状数组_卡常
    [国家集训队]矩阵乘法 整体二分
    三维偏序(陌上花开) CDQ分治
    博客园美化之旅第一天(CSS图层关系,背景相关设置,字体相关设置)
    力扣题目解答自我总结(反转类题目)
    python插件,pycharm基本用法,markdown文本编写,jupyter notebook的基本操作汇总
    关于小程序websocket全套解决方案,Nginx代理wss
  • 原文地址:https://www.cnblogs.com/forevertime/p/9246262.html
Copyright © 2011-2022 走看看