用C#获取字节的大小
我有一个class,我想检查它的领域,并最终报告每个字段有多less字节。 我假设所有字段的types是Int32,字节等
我怎样才能轻松找出该字段需要多less字节?
我需要像这样的东西:
Int32 a; // int a_size = a.GetSizeInBytes; // a_size should be 4
你基本上不能。 它将取决于填充,这可能基于您正在使用的CLR版本和处理器等。如果假定它没有对其他对象的引用,则可以更容易地计算出对象的总大小:创build一个大数组,使用GC.GetTotalMemory作为基点,使用对你的types的新实例的引用来填充数组,然后再次调用GetTotalMemory。 从另一个值中取一个值,除以实例数。 您应该事先创build一个单一的实例,以确保没有新的JITted代码贡献的数量。 是的,这听起来像是哈克,但是现在我已经用它来达到很好的效果。
就在昨天,我想这是一个很好的主意,为此写一个辅助类。 让我知道你是否有兴趣。
编辑:还有两个build议,我想解决他们两个。
首先, sizeof运算符:这只显示了types在抽象中占用了多less空间,没有在其周围应用填充。 (它在结构中包含填充,但不在另一种types中应用于该types的variables的填充)。
接下来, Marshal.SizeOf :这只在编组之后显示非托pipe大小,而不是内存中的实际大小。 正如文档明确指出:
返回的大小实际上是非托pipetypes的大小。 对象的非托pipe和pipe理大小可能不同。 对于字符types,大小受应用于该类的CharSet值的影响。
再次,填充可以有所作为。
只是为了澄清我的意思是关于填充是相关的,考虑这两个类:
class FourBytes { byte a, b, c, d; } class FiveBytes { byte a, b, c, d, e; }
在我的x86盒子上,FourBytes的一个实例需要12个字节(包括开销)。 FiveBytes的一个实例需要16个字节。 唯一的区别是“e”variables – 那么需要4个字节? 那么,有点…而不是。 很显然,你可以从FiveBytes中删除任何单个variables,将大小降回到12个字节,但这并不意味着每个variables都占用4个字节(考虑全部删除!)。 单个variables的成本并不是一个很有意义的概念。
根据问题的需要,Marshal.SizeOf可能会或可能不会给你想要的。 (在Jon Skeet发表他的答案之后编辑)。
using System; using System.Runtime.InteropServices; public class MyClass { public static void Main() { Int32 a = 10; Console.WriteLine(Marshal.SizeOf(a)); Console.ReadLine(); } }
请注意,正如jkersch所说,可以使用sizeof,但不幸的是只能使用值types。 如果你需要一个类的大小,Marshal.SizeOf是要走的路。
Jon Skeet已经说明了为什么sizeof和Marshal.SizeOf都不是完美的。 我想问题需要决定是否可以接受他的问题。
从Jon Skeets的食谱中,我试图让他所指的帮手类。 欢迎提出改进build议。
public class MeasureSize<T> { private readonly Func<T> _generator; private const int NumberOfInstances = 10000; private readonly T[] _memArray; public MeasureSize(Func<T> generator) { _generator = generator; _memArray = new T[NumberOfInstances]; } public long GetByteSize() { //Make one to make sure it is jitted _generator(); long oldSize = GC.GetTotalMemory(false); for(int i=0; i < NumberOfInstances; i++) { _memArray[i] = _generator(); } long newSize = GC.GetTotalMemory(false); return (newSize - oldSize) / NumberOfInstances; } }
用法:
应该用一个生成T的新实例的Func创build。确保每次都不返回相同的实例。 例如,这将是罚款:
public long SizeOfSomeObject() { var measure = new MeasureSize<SomeObject>(() => new SomeObject()); return measure.GetByteSize(); }
这可以间接完成,而不考虑alignment。 引用types实例的字节数等于服务字段大小+types字段大小。 服务字段(32x,每个4字节,64×8字节):
- Sysblockindex
- 指向方法表的指针
- +可选(仅用于数组)数组大小
所以,对于没有任何文件的类,他的实例在32x机器上需要8个字节。 如果它是一个字段的类,则引用同一个类实例,所以,这个类需要(64x):
Sysblockindex + pMthdTable + class = 8 + 8 + 8 = 24个字节的引用
如果它是值types,它没有任何实例字段,因此在只有他的文件大小。 例如,如果我们有一个int字段的结构,那么在32x机器上,它只需要4个字节的内存。
我不得不将这一切都归结为IL级别,但是我终于把这个function带到了C#中,并带有一个非常小的库。
你可以在bitbucket中获得(BSD许可)
示例代码:
using Earlz.BareMetal; ... Console.WriteLine(BareMetal.SizeOf<int>()); //returns 4 everywhere I've tested Console.WriteLine(BareMetal.SizeOf<string>()); //returns 8 on 64-bit platforms and 4 on 32-bit Console.WriteLine(BareMetal.SizeOf<Foo>()); //returns 16 in some places, 24 in others. Varies by platform and framework version ... struct Foo { int a, b; byte c; object foo; }
基本上,我所做的是围绕IL指令的sizeof
一个快速的类方法封装。 这条指令将获得一个对象将使用的引用的原始内存量。 例如,如果你有一个T
数组,那么sizeof
指令会告诉你每个数组元素有多less个字节。
这与C#的sizeof
操作符是截然不同的。 首先,C#只允许纯粹的值types,因为实际上不可能以静态的方式获得其他任何东西的大小。 相反, sizeof
指令在运行时级别上工作。 所以,无论在这个特定的实例中引用一个types的内存多less都会被返回。
您可以在我的博客上看到更多信息和更深入的示例代码
如果您有types,请使用sizeof运算符。 它会以字节的forms返回types的大小。 例如
Console.WriteLine(的sizeof(int)的);
会输出:
4
您可以使用方法重载来确定字段大小:
public static int FieldSize(int Field) { return sizeof(int); } public static int FieldSize(bool Field) { return sizeof(bool); } public static int FieldSize(SomeStructType Field) { return sizeof(SomeStructType); }