【问题标题】:What is the difference between inheriting from Abstract class vs Inheriting from a similar Concrete class in terms of memory consumption in C#?在 C# 中的内存消耗方面,从抽象类继承与从类似的具体类继承有什么区别?
【发布时间】:2017-12-12 09:46:26
【问题描述】:

我有两个这样的课程:

public abstract class A
{
  public int TheInt {get;set;}
  public string GetString(double dbl)
   {
       return dbl.ToString();
   }
}

public class B
{
  public int TheInt {get;set;}
  public string GetString(double dbl)
   {
       return dbl.ToString();
   }
}

我还有另外两个类,每个类都从 A 或 B 派生:

public class C : A
{
}

public class D : B
{
}

我有两个这样的对象:

C objC = new C();
D objD = new D();

objC 和 objD 在内存消耗方面会有什么不同吗?请解释一下。

【问题讨论】:

  • 这并不意味着冒犯,但您应该更多地了解abstract 的真正含义。它与内存消耗无关(不,接口不需要0字节)。
  • 内存大小等于对象中字段的总和加上继承字段的大小。 abstract 关键字没有任何作用,它会影响方法。
  • @Tim Schmelter,谢谢,我用谷歌搜索并阅读了它,得出的结论是内存消耗没有差异(我什至做了一个基准测试并计算了垃圾中的内存使用情况收藏)。但是,我在想我可能错过了什么,所以我决定联系社区进行确认。

标签: c# .net inheritance memory memory-management


【解决方案1】:

在内存消耗方面会有什么不同吗? objC 和 objD?

没有。重要的是实际的 instantiated 类(即在调用 new ... 时)。只有当您创建一个类的实例时,才会分配内存。其内存量等于实例化的实际类。指向该实例的 reference 类型与您的内存消耗完全无关。话虽如此,因为您的两个 实例化CD 具有相同的成员,它们也具有相同的内存占用空间。

另一方面,如果您要实例化一个非抽象的基类B的实例,您可能会有一些不同,因为它的成员可能少于您的派生类D(例如D还包含一个成员FurtherProperty,它不是B的一部分)。

【讨论】:

  • 谢谢。这就是我要找的。​​span>
【解决方案2】:

抽象类是一个有一些例外的类,两者都可以有构造函数和方法,运行时不会创建单独的基类和子类的实例。所以两者在内存消耗方面没有什么可区分的。

【讨论】:

    【解决方案3】:

    我针对该问题运行了如下基准测试,得出的结论是 objC 和 objD 的内存消耗相同

    class Program
    {
        static void Main(string[] args)
        {
            BenchmarkC(); //Gives 24
            //BenchmarkD(); //Gives 24
        }
    
        static void BenchmarkC()
        {
            long StopBytes = 0;
            long StartBytes = System.GC.GetTotalMemory(true);
            C objC = new C();
            StopBytes = System.GC.GetTotalMemory(true);
            GC.KeepAlive(objC);
            Console.WriteLine(StopBytes - StartBytes);
    
            Console.ReadKey();
        }
    
        static void BenchmarkD()
        {
            long StopBytes = 0;
            long StartBytes = System.GC.GetTotalMemory(true);
            D objD = new D();
            StopBytes = System.GC.GetTotalMemory(true);
            GC.KeepAlive(objD);
            Console.WriteLine(StopBytes - StartBytes);
    
            Console.ReadKey();
        }
    }
    
    public abstract class A
    {
        public int TheInt { get; set; }
        public string GetString(double dbl)
        {
            return dbl.ToString();
        }
    }
    
    public class B
    {
        public int TheInt { get; set; }
        public string GetString(double dbl)
        {
            return dbl.ToString();
        }
    }
    
    public class C : A
    {
    }
    
    public class D : B
    {
    }
    

    感谢大家的帮助。 附言。如果重要的话,我会在 .NET Core 2.0 控制台应用程序中运行基准测试。

    【讨论】:

      【解决方案4】:

      以下是抽象类和普通类继承的简化IL代码:

      不是抽象的:

      C#

      public class NotAbstract
      {
          public void PrintOut()
          {
              Console.WriteLine(nameof(NotAbstract));
          }
      }
      
      class Program : NotAbstract
      {
          static void Main(string[] args)
          {
              var p = new Program();
              p.PrintOut();
          }
      }
      

      IL

      .class public auto ansi beforefieldinit Abstract_Test_Abstract.NotAbstract
             extends [mscorlib]System.Object
      {
        .method public hidebysig instance void 
                PrintOut() cil managed
        {
      //000012:         {
          IL_0000:  nop
      //000013:             Console.WriteLine(nameof(NotAbstract));
          IL_0001:  ldstr      "NotAbstract"
          IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
          IL_000b:  nop
      //000014:         }
          IL_000c:  ret
        } // end of method NotAbstract::PrintOut
      
        .method public hidebysig specialname rtspecialname 
                instance void  .ctor() cil managed
        {
        } // end of method NotAbstract::.ctor
      
      } // end of class Abstract_Test_Abstract.NotAbstract
      
      .class private auto ansi beforefieldinit Abstract_Test_Abstract.Program
             extends Abstract_Test_Abstract.NotAbstract
      {
        .method private hidebysig static void  Main(string[] args) cil managed
        {
          .entrypoint
          .maxstack  1
          .locals init ([0] class Abstract_Test_Abstract.Program p)
      //000012:         {
          IL_0000:  nop
      //000013:             var p = new Program();
          IL_0001:  newobj     instance void Abstract_Test_Abstract.Program::.ctor()
          IL_0006:  stloc.0
      //000014:             p.PrintOut();
          IL_0007:  ldloc.0
          IL_0008:  callvirt   instance void Abstract_Test_Abstract.NotAbstract::PrintOut()
          IL_000d:  nop
      //000015:         }
          IL_000e:  ret
        } // end of method Program::Main
      
        .method public hidebysig specialname rtspecialname 
                instance void  .ctor() cil managed
        {
        } // end of method Program::.ctor
      
      } // end of class Abstract_Test_Abstract.Program
      

      摘要:

      C#

      public abstract class IsAbstract
      {
          public abstract void PrintOut();
      }
      
      class Program : IsAbstract
      {
          static void Main(string[] args)
          {
              var p = new Program();
              p.PrintOut();
          }
      
          public override void PrintOut()
          {
              Console.WriteLine(nameof(IsAbstract));
          }
      }
      

      IL

      .class public abstract auto ansi beforefieldinit Abstract_Test_NotAbstract.IsAbstract
             extends [mscorlib]System.Object
      {
        .method public hidebysig newslot abstract virtual 
                instance void  PrintOut() cil managed
        {
        } // end of method IsAbstract::PrintOut
      
        .method family hidebysig specialname rtspecialname 
                instance void  .ctor() cil managed
        {
        } // end of method IsAbstract::.ctor
      
      } // end of class Abstract_Test_NotAbstract.IsAbstract
      
      .class private auto ansi beforefieldinit Abstract_Test_NotAbstract.Program
             extends Abstract_Test_NotAbstract.IsAbstract
      {
        .method private hidebysig static void  Main(string[] args) cil managed
        {
      //000012:         {
          IL_0000:  nop
      //000013:             var p = new Program();
          IL_0001:  newobj     instance void Abstract_Test_NotAbstract.Program::.ctor()
          IL_0006:  stloc.0
      //000014:             p.PrintOut();
          IL_0007:  ldloc.0
          IL_0008:  callvirt   instance void Abstract_Test_NotAbstract.IsAbstract::PrintOut()
          IL_000d:  nop
      //000015:         }
          IL_000e:  ret
        } // end of method Program::Main
      
        .method public hidebysig virtual instance void 
                PrintOut() cil managed
        {
          .maxstack  8
      //000016: 
      //000017:         public override void PrintOut()
      //000018:         {
          IL_0000:  nop
      //000019:             Console.WriteLine(nameof(IsAbstract));
          IL_0001:  ldstr      "IsAbstract"
          IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
          IL_000b:  nop
      //000020:         }
          IL_000c:  ret
        } // end of method Program::PrintOut
      
        .method public hidebysig specialname rtspecialname 
                instance void  .ctor() cil managed
        {
        } // end of method Program::.ctor
      
      } // end of class Abstract_Test_NotAbstract.Program
      

      如您所见,没有任何额外内存消耗的证据。

      【讨论】:

      • 哇。谢谢你的详细解释。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多