前言
内存对齐的方式有三种,测试需要引用命名空间using System.Runtime.InteropServices;
namespace System.Runtime.InteropServices
{
[ComVisible(true)]
public enum LayoutKind
{
Sequential = 0,
Explicit = 2,
Auto = 3
}
}
一、LayoutKind.Sequential
顺序对齐,这种是默认的内存对齐方式,会按照struct内最大成员长度进行依次对齐,所以可能会在一定程度上浪费内存
[StructLayout(LayoutKind.Sequential)]
struct StructA // 预想是int4字节,char2字节总共6字节,但因为内存对齐,struct的总长度等于成员最大长度的整数倍,所以一个StructA却占了8字节(int换成long整个StructA的长度就是16)
{
public int num;
public char ch;
}
void Start()
{
StructA stru = new StructA();
Debug.LogError("num的长度:" + Marshal.SizeOf(stru.num));
Debug.LogError("ch的长度:" + Marshal.SizeOf(stru.ch));
Debug.LogError("StructA的长度:" + Marshal.SizeOf(stru));
}
二、LayoutKind.Explicit
精确对齐,采用这种方式CLR会按照程序的设置对内存进行精确对齐
[StructLayout(LayoutKind.Explicit)]
struct StructA
{
[FieldOffset(0)]
public int num;
[FieldOffset(0)]
public char ch;
}
void Start()
{
StructA stru = new StructA();
Debug.LogError("num的长度:" + Marshal.SizeOf(stru.num));
Debug.LogError("ch的长度:" + Marshal.SizeOf(stru.ch));
Debug.LogError("StructA的长度:" + Marshal.SizeOf(stru));
stru.num = 0;
stru.ch = 'a';
Debug.LogError("stru.num:" + stru.num);
}
[FieldOffset(0)]
意味着内存没有任何偏移,可以看出,这种情形下会造成同一个字节下存储了两条数据,当改变了其中一条时,另外一条也被改变了,所以使用时要注意偏移量
三、LayoutKind.Auto
自动对齐,CLR会调整struct 中成员的顺序来自动对齐以使实例占用尽可能少的内存,同时会进行一定字节的内存对齐
[StructLayout(LayoutKind.Auto)]
struct StructA
{
public int num;
public char ch;
}
void Start()
{
StructA stru = new StructA();
Debug.LogError("num的长度:" + Marshal.SizeOf(stru.num));
Debug.LogError("ch的长度:" + Marshal.SizeOf(stru.ch));
//Debug.LogError("StructA的长度:" + Marshal.SizeOf(stru));
unsafe
{
Debug.LogError("StructA的长度:" + sizeof(StructA));
}
}
注意:此处Marshal.SizeOf(stru)会报错ArgumentException: Type StructA cannot be marshaled as an unmanaged structure.Parameter name: t
,而sizeof(StructA)
又属于不安全代码,所以对代码做了点改动