我有一个类,我要检查它的领域和报告每个领域最终有多少字节需要。 我假定所有字段都是Int32类型,字节,等等。
我怎样才能找出容易多少字节并现场取?
我需要这样的东西:
Int32 a;
// int a_size = a.GetSizeInBytes;
// a_size should be 4
我有一个类,我要检查它的领域和报告每个领域最终有多少字节需要。 我假定所有字段都是Int32类型,字节,等等。
我怎样才能找出容易多少字节并现场取?
我需要这样的东西:
Int32 a;
// int a_size = a.GetSizeInBytes;
// a_size should be 4
你不能,基本上是这样。 这将取决于填充,这很可能是基于您正在使用的CLR版本和处理器等,这是比较容易制定出一个物体的总规模,假设它具有对其他对象的引用:创建一个大阵,使用GC.GetTotalMemory一个基点,充满你的类型的新实例引用数组,然后再打电话GetTotalMemory。 取一个值与其他走,并通过实例的数量划分。 你或许应该事先创建一个实例,以确保没有新的实时编译代码有助于号码。 是的,这是因为它的声音哈克 - 但我以前现在使用,效果良好。
就在昨天,我在想这将是一个好主意,写一个小的辅助类此。 让我知道如果你有兴趣。
编辑:有两个其他的建议,我想解决他们。
首先, 的sizeof操作符:这只能说明该类型在抽象占用多少空间了,没有施加绕着它填充。 (它包括一个结构内填充,但施加到另一种类型的内该类型的变量未填充)。
接下来, Marshal.SizeOf :这只能说明在内存编组,而不是实际尺寸后的非托管大小。 由于文件明确规定:
返回的大小非托管类型的实际大小。 对象的非托管和托管尺寸可以不同。 对于字符的类型,大小由施加到该类别的charset值的影响。
再次,填充可以有所作为。
只是为了澄清我的意思大约正在填充相关,考虑这两个类:
class FourBytes { byte a, b, c, d; }
class FiveBytes { byte a, b, c, d, e; }
在我的x86机器,FourBytes的一个实例,需要12个字节(包括间接费用)。 FiveBytes的实例需要16个字节。 唯一的区别是“E”变量 - 这是否占用4个字节? 嗯,有点......和排序的不是。 显然相当,你可以从FiveBytes消除任何单变量获得规模回落到12个字节,但是,这并不意味着每个变量占用4个字节(想想去除所有的人!)。 单个变量的成本只是不是一个概念,这使得有很大的意义在这里。
根据questionee的需求,Marshal.SizeOf可能会或可能不会给你想要的东西。 (乔恩斯基特编辑后发布了他的答案)。
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可以使用,但遗憾的是只值类型。 如果你需要一个阶级的大小,Marshal.SizeOf是要走的路。
乔恩斯基特奠定了为什么既不的sizeof也不Marshal.SizeOf是完美的。 我猜questionee需要据此决定是否或者是接受他的问题。
从他的回答乔恩长柄水杓食谱我试图让助手类,他指的。 提出改进建议,欢迎。
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键创建。 例如,这将是罚款:
public long SizeOfSomeObject()
{
var measure = new MeasureSize<SomeObject>(() => new SomeObject());
return measure.GetByteSize();
}
我不得不熬下来一路IL的水平,但我终于得到这个功能集成到C#有一个很小的图书馆。
你可以得到它(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;
}
基本上,我所做的是写周围快速的类方法封装sizeof
IL指令。 该指令将得到的存储器对一个对象的引用将使用原始量。 举例来说,如果你有数组T
,那么sizeof
指令会告诉你每个数组元素多少字节与众不同的是。
这是C#的非常不同sizeof
操作符。 首先,C#只允许纯值类型,因为它不是真的有可能得到的以静态方式别的大小。 相比之下, sizeof
指令工作在运行时的水平。 因此,然而多少内存的类型的引用此特定实例期间,将使用将被退回。
你可以看到一些更多的信息,有点更深入的示例代码在我的博客
它可以间接地完成,不考虑对齐。 引用类型实例的字节数等于服务字段大小+类型字段大小。 服务字段(32倍需要4字节,每字节,64×8字节):
因此,对于没有任何的Fileds类,他的实例需要32倍的机上8个字节。 如果它是类一个字段,在相同的类的实例参考,所以,这个类为(64×):
上类= 8 + 8 + 8 = 24个字节Sysblockindex + pMthdTable +参考
如果是值类型,它没有任何实例字段,因此只需要他的Fileds大小。 例如,如果我们有结构具有一个int字段,然后32X机器上只需要4个字节的存储器。
如果你有型,使用sizeof操作符。 它将在字节返回type`s大小。 例如
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); }
简单的方法是: int size = *((int*)type.TypeHandle.Value + 1)
我知道这是实施细节,但GC依赖于它,它需要尽量靠近启动方法表的效率,再加上考虑到GC复杂代码是如何没有人会敢改变它在未来。 事实上,它适用于.NET框架+ .NET核心的每一个次要/主要版本。 (目前无法测试1.0)
如果你想更可靠的方式,发出一个结构在动态组件与[StructLayout(LayoutKind.Auto)]
与在相同的顺序完全相同的领域,利用其大小与的sizeof IL指令。 你可能想发出结构简单地返回该值范围内的静态方法。 然后添加对对象标头2 * IntPtr.Size。 这应该给你确切的价值。
但是,如果你的类从另一个类派生,你需要找到seperatly基类的每个大小,并将它们添加+ 2 *再次Inptr.Size的头。 您可以通过获取的字段做BindingFlags.DeclaredOnly
标志。