【问题标题】:Where does CLR store methods for instances of one typeCLR 在哪里存储一种类型实例的方法
【发布时间】:2015-01-25 22:58:21
【问题描述】:
class MyClass
{
     public string MyProperty { get; set; }

     public void MyMethod()
     {
          //Do something difficult here
          //100500 lines of code here ...
     }
}

我们有很多 MyClass 的实例。

CLR 是否会为该类的任何实例创建这个非常耗费内存的MyMethod()

【问题讨论】:

  • 一个方法中有 100500 行代码!?
  • 100500 行代码我很想看看这个方法吗?
  • god class 足以证明一个全新的宗教是正当的
  • 100500 - 惯用用法表示“非常大的数字”。这个问题纯粹是假设性的。

标签: c# .net clr


【解决方案1】:

不,它没有。当我们第一次调用此方法时,此方法将编译一次。然后编译后的代码将被MyClass 类型的任何实例使用。因此,任何性能损失仅发生在此方法的第一次调用中,该方法从 IL 代码编译为本机代码。

在下面,我发布了两张图片,可能会更清楚地说明这一点:

如需了解更多信息,请查看本书CLR via C#

【讨论】:

    【解决方案2】:

    假设你的意思是

    CLR 是否为类的每个 实例创建这个非常耗费内存的 MyMethod()?

    不,类方法的代码只为每个方法生成一次。

    但是,与类的每个新实例相关联的 数据 将被分配并存储在托管堆上(它定义了实例的this 位置),并且每个方法在一个类实例将silently pass the this实例的引用(指针)作为方法的隐藏参数。

    以这个 sn-p 为例:

    var foo = new Foo();
    var anotherFoo = new Foo();
    foo.Bar();
    anotherFoo.Bar();
    

    反汇编显示了两个this 引用如何作为参数传递给对同一Bar 方法的调用。 (实际上,您可以看到对两个对象也进行了相同的 Constructor 调用)。

                var foo = new Foo();
    00000038  mov         ecx,592758h 
    0000003d  call        FFC8F840
    00000042  mov         dword ptr [ebp-4Ch],eax 
    00000045  mov         ecx,dword ptr [ebp-4Ch] 
    00000048  call        FFCA9F00 
    0000004d  mov         eax,dword ptr [ebp-4Ch] 
    00000050  mov         dword ptr [ebp-44h],eax ** [ebp-44h] = this for foo 
                var anotherFoo = new Foo();
    00000053  mov         ecx,592758h 
    00000058  call        FFC8F840
    0000005d  mov         dword ptr [ebp-50h],eax 
    00000060  mov         ecx,dword ptr [ebp-50h] 
    00000063  call        FFCA9F00 
    00000068  mov         eax,dword ptr [ebp-50h] 
    0000006b  mov         dword ptr [ebp-48h],eax  ** [ebp-48h] = this for anotherFoo
                foo.Bar();
    0000006e  mov         ecx,dword ptr [ebp-44h] ** pass foo to `Bar()` across in ecx
    00000071  cmp         dword ptr [ecx],ecx 
    00000073  call        FFCA9EF8   ** Bar()'s address
    00000078  nop 
                anotherFoo.Bar();
    00000079  mov         ecx,dword ptr [ebp-48h] ** pass anotherFoo to `Bar()` in ecx
    0000007c  cmp         dword ptr [ecx],ecx 
    0000007e  call        FFCA9EF8 ** You can see the same "Bar()" address is being called
    00000083  nop 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多