zil*_*n01 7 c# generics polymorphism performance
我注意到在C#中,与C++不同,您可以组合虚拟和通用方法.例如:
using System.Diagnostics;
class Base {
public virtual void Concrete() {Debug.WriteLine("base concrete");}
public virtual void Generic<T>() {Debug.WriteLine("base generic");}
}
class Derived : Base {
public override void Concrete() {Debug.WriteLine("derived concrete");}
public override void Generic<T>() {Debug.WriteLine("derived generic");}
}
class App {
static void Main() {
Base x = new Derived();
x.Concrete();
x.Generic<PerformanceCounter>();
}
}
Run Code Online (Sandbox Code Playgroud)
考虑到任意数量的版本Generic<T>可以被实例化,它看起来并不像标准vtbl的方法可以用于解决方法调用,实际上它不是.这是生成的代码:
x.Concrete();
mov ecx,dword ptr [ebp-8]
mov eax,dword ptr [ecx]
call dword ptr [eax+38h]
x.Generic<PerformanceCounter>();
push 989A38h
mov ecx,dword ptr [ebp-8]
mov edx,989914h
call 76A874F1
mov dword ptr [ebp-4],eax
mov ecx,dword ptr [ebp-8]
call dword ptr [ebp-4]
Run Code Online (Sandbox Code Playgroud)
额外的代码似乎是根据通用参数查找动态vtbl,然后调用它.有没有人写过这个实现的具体细节?与非通用案例相比,它的表现如何?
.NET泛型实现可以轻松地以良好的性能处理这种情况。我前一段时间写了一篇关于它的博客文章。
Micosoft Research的这篇论文是查找有关CLR如何实现泛型的信息的最佳资源之一。
您了解有关vtable的信息。当JIT编译器偶然发现通用类型时,CLR如何为通用类型创建可执行代码,取决于通用类型参数。值类型和引用类型的处理不同。
虽然可执行代码(实例化本机映像)在实例化之间共享所有引用类型的通用类型参数,但与实例化实例(对象)关联的vtable对于具体参数类型而言是唯一的。
以下是上述论文的相关报价:
4.2对象表示CLR的垃圾回收堆中的对象由vtable指针表示,后跟对象的内容(例如,字段或数组元素)。vtable的主要作用是虚拟方法分配:它包含由对象的类定义或继承的每个方法的代码指针。但是,至少对于简单的类类型,在vtable和类之间存在一一对应的情况下,它也可以用于表示对象的类型。当以这种方式使用vtable时,我们将其称为类型的类型句柄。在基于完全专业化的多态实现中,精确运行时类型的概念是免费提供的,因为相同参数化类型的不同实例具有不同的vtable。
List<string>和List<object>。这两个实例化的vtables将是相同的,因此我们需要某种方式在运行时表示实例化。
...
[对于每个实例,我们用一个指向组合的vtable-instantiation结构的指针替换vtable指针,并在每个实例中复制[结构]。