sizeof仅适用于编译期大小确定的非托管类型:内置数值类型、枚举及纯值类型struct;含引用字段的class或struct不可用,否则编译报错。

sizeof 只能用于非托管类型,且多数结构体根本不能用它——别指望靠它查 class 或含引用字段的 struct 大小。
哪些类型能直接用 sizeof?
仅限编译期确定大小的非托管类型:
- 所有内置数值类型:
int、long、float、double、bool、char等(sizeof(int)恒为 4) - 枚举类型(底层为整型,如
enum E : short→sizeof(E)是 2) - 纯值类型的
struct:所有字段必须是上述类型或同样满足条件的嵌套struct,且不能含string、object、数组、类引用等
一旦结构体里加了个 string 字段或 List<int></int>,sizeof 编译直接报错:“Cannot take the address of, get the size of, or declare a pointer to a managed type”。
sizeof 和 Marshal.SizeOf 的区别在哪?
两者返回值经常不同,原因很实在:
-
sizeof返回的是 CLR 在栈上实际分配的大小,包含结构体内存对齐填充(padding),是运行时真实占用空间 -
Marshal.SizeOf返回的是该类型封送到非托管环境(比如 P/Invoke 调用 C DLL)时所需的大小,遵循 C ABI 规则,可能忽略某些填充或按不同对齐策略计算 - 例如一个含两个
byte和一个int的 struct,在 64 位进程下:sizeof可能是 12(因 int 对齐到 4 字节边界,中间插 2 字节 padding),而Marshal.SizeOf可能是 8(C 风格紧凑布局)
别混用:需要内存布局控制(如 socket 序列化、内存映射)时看 Marshal.SizeOf;想知栈上开销或做 unsafe 指针运算,才用 sizeof。
怎么安全地查任意对象(包括 class 和复杂 struct)的大小?
没有通用、准确、零开销的办法。但根据场景有务实选择:
- 纯诊断/估算:用
GC.GetTotalMemory前后差值(需强制 GC,不准,只适合粗略对比) - 结构体 + 封送需求:用
Marshal.SizeOf<t>()</t>,但必须加[StructLayout(LayoutKind.Sequential)],否则行为未定义 - 运行时实例大小(含堆对象):没标准 API;
System.Runtime.InteropServices.Marshal.AllocHGlobal+GetObjectData不现实;真实项目中通常靠分析工具(dotMemory、PerfView)采样,而非代码硬算 - 误以为
sizeof能查string或List<t></t>—— 它连编译都过不了,别试
真正容易被忽略的一点:sizeof 是编译时常量,不是运行时函数;你写 sizeof(int),C# 编译器直接替换成数字 4,不生成任何 IL 指令。所以它快得没意义,但也因此毫无灵活性。











