代码之家  ›  专栏  ›  技术社区  ›  zildjohn01

泛型C#方法多态性的性能

  •  6
  • zildjohn01  · 技术社区  · 15 年前

    我注意到,在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>();
        }
    }
    

    考虑到 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] 
    

    额外的代码似乎是根据泛型参数查找动态vtbl,然后调用它。有人写过这个实现的细节吗?与非通用情况相比,它的性能如何?

    2 回复  |  直到 15 年前
        1
  •  5
  •   Johannes Rudolph    15 年前

    NET泛型实现可以轻松地处理这样的场景,并且具有非常好的性能。我写了一封信 blog post 关于这件事。

    查找有关CLR如何实现泛型的信息的最佳资源之一是 paper 米科索夫特研究所。

    你对vtable的看法是对的。当JIT编译器偶然发现泛型类型时,CLR如何为泛型类型创建可执行代码取决于泛型类型参数。值类型和引用类型的处理方式不同。

    以下是上述论文的相关引用:

    由vtable指针表示 其次是对象内容 (例如ELD或数组元素)。这个 分派:它包含一个代码指针 对于简单的类类型,至少, vtables与vtables的对应关系 表示对象类型。当 vtable的用法我们称之为 类型类型句柄。在一个 基于多态性的实现 完全专业化的概念 相同的参数化类型具有不同的 在中的不同用户之间共享- 例如 List<string> List<object> . 的vtables 两个实例是相同的, 所以我们需要一些方法来代表 运行时的实例化。

    ...

    [对于每个实例化,我们]将vtable指针替换为指向组合vtable的指针- 和实例化结构,并在每次实例化时复制它[结构]。

        2
  •  0
  •   thecoop    15 年前

    因此,我猜测泛型类型/方法的每个实现都有自己的vtable,并且代码正在执行“查找泛型实现”,然后在找到的实现上执行“查找vtable重写”。