【问题标题】:Size of A Class (object) in .NET.NET 中类(对象)的大小
【发布时间】:2015-11-09 00:53:28
【问题描述】:

如何确定.NET 中的类是大还是小?它是根据它的属性或字段的数量、它的属性/字段的数据类型来衡量的吗?或返回方法类型?它的方法的参数?其方法的访问修饰符,虚拟方法?谢谢..

 class A
{

  string x { get; set; }
}

class B 
{
  int x { get; set; }
}

在这个例子中,如果我像这样实例化 A 类和 B 类

 A objA = new A();
 B objB = new B();

类 objA 是不是更大的类,因为它拥有一个 String 属性,而 objB 只拥有一个 Int?尽管我没有为其属性设置任何值。谢谢

编辑:只是为了澄清我的问题

假设我有一堂课

public class Member
{
    public string MainEmpId { get; set; }
    public string EmpId { get; set; }
}

和另一个班级

public class User
{
    public string AccessLevel { get; set; }
    public string DateActivated { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Mi { get; set; }
    public string Password { get; set; }
    public string UserId { get; set; }
    public string UserName { get; set; }
    public string Active { get; set; }
    public string ProviderName { get; set; }        
    public string ContactPerson { get; set; }
    public string Relation { get; set; }
    public string Landline { get; set; }
    public string MobileNo { get; set; }
    public string Complaint { get; set; }
    public string Remarks { get; set; }
    public string Reason { get; set; }
    public string RoomType { get; set; }
}

如果我这样实例化它

  Member A = new Member();
  User B = new User()

对象 A 比对象 B 大吗? 我知道这是一个奇怪的问题,但我相信对象的每个实例化都会占用内存空间..

【问题讨论】:

  • 这是一个模棱两可的问题...当您说“类大小”时,您是包括类具有指针的所有引用/对象使用的内存,还是仅包括类本身和指针本身的内存用途?
  • 你的意思是内存空间吗?如果是这样,我认为您无法真正衡量它,也不应该真正关心那么多恕我直言。
  • 是的,我的意思是内存中的大小。我认为这对我很重要,因为我使用值对象,我的一些对象有 100 个属性!我将这些对象放在 List 之类的集合中。只是想知道它是否对性能有影响...
  • @Nick Craver,我的意思是实例化或使用时内存中的对象大小..
  • @CSharpNoob - 你还没有澄清任何问题,这取决于你在测量什么,当你说你存储一个字符串时,它实际上是对 another 位置的引用包含字符串的内存,但在类本身上你只存储一个指针,所以你是在计算字符串使用的空间,还是只计算指向字符串的指针?

标签: c# .net class


【解决方案1】:

类实例的大小由以下因素决定:

  • 实例中实际存储的数据量
  • 值之间需要填充
  • 内存管理使用的一些额外内部数据

所以,通常需要一个包含字符串属性的类(在 32 位系统上):

  • 8 字节用于内部数据
  • 4 个字节的字符串引用
  • 4 字节的未使用空间(以达到内存管理器可以处理的最小 16 字节)

通常需要一个包含整数属性的类:

  • 8 字节用于内部数据
  • 4 个字节的整数值
  • 4 字节的未使用空间(以达到内存管理器可以处理的最小 16 字节)

如您所见,字符串和整数属性在类中占用相同的空间,因此在您的第一个示例中,它们将使用相同的内存量。

string 属性的值当然是另一回事,因为它可能指向堆上的一个字符串对象,但那是一个单独的对象,而不是指向它的类的一部分。

对于更复杂的类,填充会发挥作用。例如,包含布尔值和字符串属性的类将使用:

  • 8 字节用于内部数据
  • 1 个字节的布尔值
  • 3 字节的填充以达到偶数 4 字节的边界
  • 4 个字节的字符串引用

请注意,这些是类的内存布局示例。确切的布局取决于框架的版本、CLR 的实现以及它是 32 位还是 64 位应用程序。由于程序可以在 32 位或 64 位系统上运行,因此编译器甚至不知道内存布局,它是在代码执行前 JIT:ed 时决定的。

【讨论】:

  • 那么,这是否意味着一个空类(没有方法和数据成员)的大小 = 12 字节?
  • @Amby:不,它将有 16 个字节的大小。在 32 位系统上,它将包含 8 个字节的内部数据和 8 个字节的未使用空间,在 64 位系统上,它将包含 16 个字节的内部数据,并且没有未使用的空间。
  • 如果我没记错的话,空类有 16 个字节,8 个字节的同步对象(浪费空间)和 8 个字节的类型指针。
【解决方案2】:

一般来说,当一个类有很多实例(非静态)字段时,它就比较大,不管它们的值是多少;类的内存最少为 12 个字节,具有引用类型的字段在 32 位系统上为 4 个字节,在 64 位系统上为 8 个字节。其他字段可以通过填充字边界来布局,这样具有四个byte 字段的类实际上可能会占用内存中的四倍四字节。但这一切都取决于运行时。

不要忘记可能隐藏在自动属性声明中的字段。由于它们在内部由一个字段支持,因此它们会增加类的大小:

public string MyProperty
{ get; set; }

请注意,以下属性对类大小没有影响,因为它不受字段支持:

public bool IsValid
{ get { return true; } }

要了解类或结构实例的内存大小:对类应用 [StructLayout(LayoutKind.Sequential)] 属性并在类型或实例上调用 Marshal.SizeOf()

[StructLayout(LayoutKind.Sequential)]
public class MyClass
{
    public int myField0;
    public int myField1;
}

int sizeInBytes = Marshal.SizeOf(typeof(MyClass));

但是,由于运行时可以按照自己的意愿在内存中布局类,因此实例使用的实际内存可能会有所不同,除非您应用 StructLayoutAttribute

【讨论】:

  • 意思是当该字段为空时,它甚至没有在内存中分配一个字节?
  • 只计算字段,而不考虑它们的值。
  • @CSharpNoob:如果字段是设置为 null 的引用类型,它仍会占用指向实例所需的字节数。它只是暂时没有指向一个。在上面的例子中,一个属性没有支持字段,所以它不需要额外的空间。
【解决方案3】:

虽然以下文章是旧文章 (.NET 1.1),但这些概念清楚地解释了 CLR 为在应用程序中实例化的对象分配内存所做的工作;它们放置在哪些堆中,它们的对象引用指针在哪里寻址,等等。

Drill Into .NET Framework Internals to See How the CLR Creates Runtime Objects

【讨论】:

    【解决方案4】:

    您也可以查看:how-much-memory-instance-of-my-class-uses。 调用构造函数后有一种简单的方法来测试对象的大小。

    【讨论】:

      【解决方案5】:

      github上有一个名为dotnetex的项目,它使用了一些魔法并显示了类或对象的大小。

      用法很简单:

      GCex.SizeOf<Object>();    // size of the type
      GCEx.SizeOf(someObject);  // size of the object;
      

      在引擎盖下它使用了一些魔法。
      要计算类型的大小,它将方法表的指针转换为内部 MethodTableInfo 结构并使用它的 Size 属性,如下所示:

      public static unsafe Int32 SizeOf<T>()
      {
          return ((MethodTableInfo *)(typeof(T).TypeHandle.Value.ToPointer()))->Size;
      }
      

      要计算一个物体的大小,它使用了很难获得的真正黑暗魔法:) 看看the code

      【讨论】:

        【解决方案6】:

        当人们说类大小时,我会假设它意味着类有多少成员,以及类有多复杂。

        但是,您的问题是我们创建类实例时所需的内存大小。我们无法确定确切的大小,因为 .Net 框架保留并让我们远离底层内存管理(这是一件好事)。即使我们现在有正确的大小,该值也可能永远正确。无论如何,我们可以确定以下内容会占用内存中的一些空间:

        1. 实例变量。
        2. 自动属性。

        所以说User 类将比Member 类占用更多内存是有道理的。

        【讨论】:

          猜你喜欢
          • 2010-10-12
          • 2012-04-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-21
          相关资源
          最近更新 更多