如何检查结构消耗的字节数?
如果我正在创build一个相对较大的结构,我如何计算它在内存中占用的字节呢?
我们可以手动做,但如果结构足够大,那么我们该怎么做呢? 有一些代码块或应用程序?
您可以使用sizeof
运算符或SizeOf
函数。
这些选项之间有一些差异,请参阅参考链接了解更多信息。
无论如何,使用该函数的一个好方法是使用这样的generics方法或扩展方法:
static class Test { static void Main() { //This will return the memory usage size for type Int32: int size = SizeOf<Int32>(); //This will return the memory usage size of the variable 'size': //Both lines are basically equal, the first one makes use of ex. methods size = size.GetSize(); size = GetSize(size); } public static int SizeOf<T>() { return System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)); } public static int GetSize(this object obj) { return System.Runtime.InteropServices.Marshal.SizeOf(obj); } }
在计算机工程中,结构已经很麻烦了很长时间了。 他们的内存布局非常依赖于硬件。 为了使它们高效,它们的成员必须alignment,以便CPU可以快速读写数据,而不必复用字节以适应内存总线宽度。 每个编译器都有自己的打包成员的策略,通常由C或C ++程序中的#pragma pack指令引导。
没关系,而是互操作场景中的一个问题。 其中一个代码块可能会对另一个由另一个编译器编译的块做出不同的结构布局假设。 您可以在COM,.NET的祖父解决scheme中看到这一点。 COM对处理结构的支持很差。 它不支持它们作为本地自动化types,但通过IRecordInfo接口有一个解决方法。 通过在types库中显式声明结构,可以让程序在运行时发现内存布局。 哪个工作正常,但是效率很低。
.NETdevise师为解决这个问题做出了非常勇敢和正确的决定。 他们使一个结构的内存布局完全不可发现。 没有logging的方式来检索成员的偏移量。 而通过扩展,没有办法发现结构的大小。 大家最喜欢的答案,使用Marshal.SizeOf()实际上并不是解决scheme。 在调用Marshal.StructureToPtr之前, 它会返回struct的大小,这个大小需要传递给Marshal.AllocCoTaskMem()。 根据与结构关联的[StructLayout]属性排列和alignment结构成员。 注意这个属性对于结构来说不是必需的(比如它是用于类),运行时实现了一个使用成员声明顺序的默认属性。
一个非常好的布局不可发现的副作用是CLR可以玩弄它的技巧。 当包装结构的成员和alignment,布局可以得到不存储任何数据的洞。 称为填充字节。 考虑到布局是不可发现的,CLR实际上可以使用填充。 如果它足够小以适应这样的洞,它就会移动一个成员。 现在,您将得到一个结构,其大小比通常所需的结构布局要小。 而且,值得注意的是,Marshal.SizeOf()将返回结构大小的错误值,它会返回一个太大的值。
长话短说,没有通用的方法来以编程方式获得结构大小的准确值。 最好的办法就是不要问这个问题。 Marshal.SizeOf()会给你一个猜测,假设结构是blittable。 如果你由于某种原因需要一个精确的值,那么你可以查看一个方法的生成机器代码,该方法声明结构types的局部variables,并将其与没有局部variables的同一个方法进行比较。 您将看到堆栈指针调整的不同之处,即方法顶部的“sub esp,xxx”指令。 当然,这将取决于架构,您通常会在64位模式下获得更大的结构。
您可以对不包含任何引用types的字段或属性的用户定义结构使用sizeof()
关键字,也可以使用Marshal.SizeOf(Type)
或Marshal.SizeOf(object)
来获取非托pipe大小的types或具有顺序或显式布局的结构 。
我用CIL ( .NET的汇编语言)编写了一个小小的库,用来展示C#中不可用的一些简洁的function。 我打破了sizeof
指令。
它与C#中的sizeof
运算符显着不同。 基本上,它获得了一个结构(或引用types,这有一些优化有趣的),包括填充和所有的大小。 所以,如果你要创build一个T
的数组,那么你可以使用sizeof来确定每个数组元素之间的距离( 以字节为单位) 。 这也是完全可以validation和pipe理的代码。 请注意,在单声道有一个错误(3.0前?)这将导致sizeof引用types被错误地报告,这将扩展到包含引用types的结构。
无论如何,您可以从BitBucket下载BSD许可的库(和CIL)。 您还可以在我的博客上看到一些示例代码和一些更多的细节。
你想使用System.Runtime.InteropServices.Marshal.SizeOf() :
struct s { public Int64 i; } public static void Main() { s s1; s1.i = 10; var s = System.Runtime.InteropServices.Marshal.SizeOf(s1); }
您也可以使用System.Runtime.InteropServices.Marshal.SizeOf()
来获取以字节为单位的大小。
在.NET Core中 ,CIL指令的sizeof
已经通过最近添加的Unsafe
类暴露出来。 添加对System.Runtime.CompilerServices.Unsafe
包的引用,只需执行以下操作:
int size = Unsafe.SizeOf<MyStruct>();
它也适用于引用types(将根据您的计算机的体系结构返回4或8)。
一个struct
应该有一个16字节的最大大小。 如果你的struct
比那个大,那么你应该使用一个class
。