2014-10-09 110 views
4

我一直在閱讀虛擬方法以及它們是如何被調用的。正如所討論的herehere,我已經得出結論,他們不應該真的如此不同。虛擬方法比非虛擬方法要慢

C#編譯器發出IL代碼,該代碼通過call IL指令調用靜態方法,並通過callvirt調用虛擬/非虛擬成員。看起來JIT的工作實際上是確定被調用的方法對象是否實際爲空。所以這兩項檢查都是一樣的。另外,正如在第一篇文章中討論的那樣,在編譯時,看起來vtables或者表格保存着方法定義的元數據,在編譯時被展平了。換句話說,這些表確切地包含了對象應該調用的方法,而不需要對繼承鏈進行遞歸搜索。

綜上所述,爲什麼虛擬方法被認爲比較慢?也許是一個間接的(如果有的話)那麼大的一筆交易?請解釋...

+0

* CLR只通過調用IL指令調用靜態方法*是有誤導性的。它是C#編譯器,它爲靜態和'callvirt'發出'call'指令作爲實例方法。其他編譯器可以自己的方式自由地實現它。 CLR與此無關。 – 2014-10-09 15:14:38

+0

@SriramSakthivel真。我會換個話。 – 2014-10-09 15:15:52

+0

相關:http://stackoverflow.com/questions/530799/what-are-the-performance-implications-of-marking-methods-properties-as-virtual – 2014-10-09 15:28:53

回答

1

您正在研究函數調用指令與直接與間接尋址之間的區別。但是間接函數調用的大部分「成本」不是調用本身,而是失去了執行需要對目標進行靜態知識的優化的機會。內聯,跨程序混疊分析等等。

1

找出要執行哪個實際方法實施將具有的一些成本,而不僅僅是知道。該成本可能非常小,並且很可能成本對於任何特定背景都是完全可以忽略的,因爲它確實不需要很長的時間。但成本是非零的,所以在特別對性能敏感的應用中,它會使的一些的差異。

+0

尋找實際的實施是反對的聲明,虛擬桌面被夷爲平地編譯時間。那麼你是否相信CLR仍然需要遵循繼承鏈?如果不是,並且如果您在對象所引用的「類型對象」的元數據中評論實際的「方法表」,對於非虛擬方法,這不是相同的情況嗎?換句話說,在編譯時對於任何給定類型的方法表槽中記錄的右偏移量是否不是平坦的? – 2014-10-09 15:22:15

+0

@FarhadAliNoo如果方法是虛擬的,則需要檢查對象的實際運行時類型,並且需要在vtable中查找該類型的給定方法的實現。對於非虛擬方法,這些都不需要發生;該方法在編譯時綁定。 – Servy 2014-10-09 15:26:17