获取一个字段的大小与C#字节获取一个字段的大小与C#字节(Getting the size of a

2019-05-08 23:01发布

我有一个类,我要检查它的领域和报告每个领域最终有多少字节需要。 我假定所有字段都是Int32类型,字节,等等。

我怎样才能找出容易多少字节并现场取?

我需要这样的东西:

Int32 a;
// int a_size = a.GetSizeInBytes;
// a_size should be 4

Answer 1:

你不能,基本上是这样。 这将取决于填充,这很可能是基于您正在使用的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个字节(想想去除所有的人!)。 单个变量的成本只是不是一个概念,这使得有很大的意义在这里。



Answer 2:

根据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需要据此决定是否或者是接受他的问题。



Answer 3:

从他的回答乔恩长柄水杓食谱我试图让助手类,他指的。 提出改进建议,欢迎。

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();
    }


Answer 4:

我不得不熬下来一路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指令工作在运行时的水平。 因此,然而多少内存的类型的引用此特定实例期间,将使用将被退回。

你可以看到一些更多的信息,有点更深入的示例代码在我的博客



Answer 5:

它可以间接地完成,不考虑对齐。 引用类型实例的字节数等于服务字段大小+类型字段大小。 服务字段(32倍需要4字节,每字节,64×8字节):

  1. Sysblockindex
  2. 指向方法表
  3. +可选的(仅用于数组)的数组大小

因此,对于没有任何的Fileds类,他的实例需要32倍的机上8个字节。 如果它是类一个字段,在相同的类的实例参考,所以,这个类为(64×):

上类= 8 + 8 + 8 = 24个字节Sysblockindex + pMthdTable +参考

如果是值类型,它没有任何实例字段,因此只需要他的Fileds大小。 例如,如果我们有结构具有一个int字段,然后32X机器上只需要4个字节的存储器。



Answer 6:

如果你有型,使用sizeof操作符。 它将在字节返回type`s大小。 例如

Console.WriteLine(的sizeof(int)的);

将输出:

4



Answer 7:

您可以使用方法重载的一招,以确定字段大小:

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); }


Answer 8:

简单的方法是: 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标志。



文章来源: Getting the size of a field in bytes with C#