Unity/C#结构体内存对齐
默认对齐行为
在 C# / Unity 中:
字段对齐:
编译器会根据字段类型自动插入 padding,使每个字段对齐到自己的自然边界。
结构体整体大小:
编译器会把结构体整体大小对齐到最大字段的大小(自然对齐)。
struct MyStruct
{
byte a; // 1 byte
int b; // 4 bytes
}
a 占 1 byte
padding 3 bytes 插入,保证 b 对齐到 4-byte 边界
结构体总大小 = 8 bytes(不是 5 bytes)
控制结构体整体对齐
C# 提供了两个主要特性:
1.[StructLayout(LayoutKind.Sequential, Pack = X)]
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential, Pack = 16)]
struct MyStruct
{
public byte a;
public int b;
}
Pack 指定字段的最大对齐,同时影响结构体整体对齐。
Unity + Burst 会遵循这个 Pack,使结构体在数组中连续排列时更容易被 SIMD 加速。
常用 Pack 值:1, 2, 4, 8, 16。
注意:设置 Pack = 16 并不保证字段都 16-byte 对齐,但会尽量按 16-byte 边界排列结构体。
2.[StructLayout(LayoutKind.Explicit)] + FieldOffset
如果你想精确控制内存布局(甚至让结构体整体 16-byte 对齐):
[StructLayout(LayoutKind.Explicit, Size = 16)]
struct MyStruct
{
[FieldOffset(0)]
public int a;
[FieldOffset(4)]
public float b;
[FieldOffset(8)]
public Vector3 c; // 12 bytes
// 由于 Size=16,整体结构体占 16 bytes
}
Size 强制结构体整体大小对齐。
FieldOffset 可以精确控制每个字段在结构体中的位置。
Burst + Jobs 可以直接用这种结构体数组做 SIMD 运算。
Unity / Burst 的注意事项
Unity 的 NativeArray 或 UnsafeUtility 访问内存时:
结构体整体对齐对性能很重要。
SIMD/Vectorized 运算要求 16-byte 或 32-byte 对齐。
可以用 UnsafeUtility.AlignOf() 查看类型实际对齐要求。
例如:
Debug.Log(UnsafeUtility.SizeOf<MyStruct>());
Debug.Log(UnsafeUtility.AlignOf<MyStruct>());
最佳实践
小结构体(<16 bytes):默认 Sequential 即可。
大结构体(>16 bytes 或用于 SIMD/Jobs):
使用 [StructLayout(LayoutKind.Sequential, Pack=16)] 或 [StructLayout(LayoutKind.Explicit, Size=16)]。
确保字段顺序按 从大到小 排列,减少 padding。
避免在结构体里放引用类型 (class 或 string)。
对于 Burst + Jobs,可以考虑使用 SoA + NativeArray 结合 SIMD,这样整体对齐最优。
小结

更多推荐

所有评论(0)