CLR Drilling Down: The Overhead of Method Calls[收藏]

 最近看到很多关于GenericsBoxing性能的讨论,大家对这两部分的性能都非常关心。其实这两个部分最终的性能表现往往会通过Method Call等等比较底层的CLR功能反映出来,如果没有对底层构造的深入了解,可能会导致新能分析的一些误差。

 

  .NET CLR通过CallCallvirt两条指令支持三种方法调用模式(另一条MSIL指令Calli和这里讨论的内容关系不大)

l         直接方法调用(Direct Method Call)

这是最简单的方法调用模式,如果C#/VB.NET编译器可以静态的解析需要调用的函数,那么编译器就直接生成Call指令,并且把目标函数的地址(实际上是一个引用标志,理解成函数地址要容易一些)直接放在MSIL指令当中。在运行时CLR也不需要进一步解析,直接调用这个引用的函数就是。例如:

    call   instance void SomeType:: SomeMethod()

 

NOTE: 有时候Compiler会生成Callvirt指令来进行直接方法调用,这时候主要目的是利用Callvirt指令的一个附带作用:当this为null的时候,它会throw exception;而Call不会。但是底层JIT生成的机器指令仍然是一条直接方法调用指令。

 

l         虚方法调用(Virtual Method Call)

这种方法和C++vptr/vtable机制类似。由于subclassoverride,编译器显然无法在编译期间识别出运行时需要调用的具体函数。所以编译器生成Callvirt指令,加上父类对应方法的引用。在运行时刻,每个Reference Type ObjectBoxed ValueType Object都有一个指向其类型信息(MethodTable)的指针,MethodTable包含了这个类定义的所有方法(可能还会有重复),并且它的函数表前部顺序保证和父类MethodTable相同。这样CLR通过Object找到对应的MethodTable,然后从MethodTable中找到与指令中引用的方法对应位置的函数入口,然后调用该方法。

    callvirt   instance bool Object::Equels(Object o)

 

l         接口方法调用(Interface Method Call)

这是.NET独有的调用方式。由于仅支持单继承,MethodTable格式上只要与自己的父类一致。但是接口实现的时候仍然可能出现C++经常提到的钻石结构或者命名冲突。.NET的解决办法是引入Interface Map:编译器产生的代码和前面的Virtual Method Call完全一致,只是引用的方法是Interface的而不是父类的;在运行时刻MethodTable当中包含了一个InterfaceMap的指针,通过InterfaceMapCLR可以找到MethodTable结构中和某个Interface结构顺序等价的一个段落,从而找到并且调用相应的接口函数。

    callvirt  instance bool IComparable::CompareTo(object o)

 

下图表示了这三种方法调用的路径。显然,直接调用通过JIT生成的机器指令最少,只需要一条x86 Call汇编指令,虚方法调用和C++vptr调用类似,需要两条机器指令,包含一个间接调用;接口调用最慢,大约需要4条机器指令,包括间接调用。

 

 

 

接下来需要做的就是正确识别出在什么情况下编译器会选择哪种调用方式,例如下面代码中的方法调用,不妨尝试分析一下。J

 

interface ITest {

       void SomeMethod();

}

 

class TestClass : ITest {

       public virtual void SomeMethod2() {

              //…

    }

 

       public void SomeMethod() {

              //…

    }

}

 

//…

ITest itest = …;

TestClass tobj = …;

 

itest.SomeMethod();      //?

tobj.SomeMethod();       //?

tobj.SomeMethod2();     //?

((TestClass)itest).SomeMethod();  //?
原文地址: http://blog.joycode.com/qqchen/posts/18890.aspx

posted @ 2004-04-10 17:42  dudu  阅读(1734)  评论(0)    收藏  举报