class MyClass
{
public string MyProperty { get; set; }
public void MyMethod()
{
//Do something difficult here
//100500 lines of code here ...
}
}
我们有很多MyClass
的实例。
CLR是否为类的任何实例创建了内存非常昂贵的MyMethod()
?
答案 0 :(得分:5)
不,不。当我们第一次调用此方法时,此方法将编译一次。然后,编译的代码将由类型MyClass
的任何实例使用。因此,只有在第一次调用此方法时才会发生任何性能损坏,IL代码将从本地编译为本机代码。
下面,我发布了两张可能更清晰的图片:
和
有关详细信息,请参阅本书CLR via C#。
答案 1 :(得分:2)
假设你的意思
CLR是否为类的每个实例创建了这个内存非常昂贵的MyMethod()?
不,代码(对于类的方法)仅为每个方法生成一次。与MyClass
的每个新实例关联的数据将存储在托管堆上,并且在实例上调用的每个方法都将silently pass the this
实例的引用(指针)作为方法的隐藏参数。
以此片段为例:
var foo = new Foo();
var anotherFoo = new Foo();
foo.Bar();
anotherFoo.Bar();
反汇编显示了两个this
引用如何作为参数传递给对同一Bar
方法的调用。 (事实上,你可以看到同样的构造函数调用也是针对这两个对象的。)
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