java中間語言匯編語言_中間語言(IL) | 學步園

一、IL與匯編語言

IL是微軟.NET平臺上衍生出的一門中間語言,.NET平臺上的各種高級語言(如C#,VB,F#)的編譯器會將各自的代碼轉化為IL。,其中包含了.NET平臺上的各種元素,如“范型”,“類”、、“接口”、“模塊”、“屬性”等等。值得注意的是,各種高級語言本身可能根本沒有這些“概念”在里頭,如IronScheme是一個在.NET平臺上的Scheme語言實現,其中根本沒有前面提到的這些IL——亦或說是.NET平臺上的名詞。IL本身并不知道自己是由哪種高級語言轉化而來的,哪種語言中有哪些特性,IL也根本不會關心。

各種語言的編譯器將:高級語言=> IL。

匯編是讓CPU直接使用的“語言”,請注意“直接”二字:一條匯編指令便是讓CPU作一件事情(如寄存器的復制,從內存中讀取數據等等),毫無二義。不同族CPU擁有不同的指令集,但是它們都有一樣的特征:指令的數量相對較少,每個指令功能都簡單之至。

由于CPU只認識匯編代碼(機器碼和匯編其實也是一一對應的,您可以這樣理解:匯編是機器碼的文字表現形式,提供了一些方便人們記憶的“助記符”),因此就算是IL也需要再次進行轉化,才能被CPU執行。這次轉化便由“JIT Compiler”(即時編譯器)完成。CLR加載了IL之后,當每個方法——請注意這是IL中的概念——第一次被執行時,就會使用JIT將IL代碼進行編譯為機器碼。與IL不同的是,CLR,JIT都是真正了解CPU的,對于同樣的IL,JIT會把它為不同的CPU架構(如x86/IA64等等)生成不同的機器碼。這也是Java/.NET中“Compile Once,Run Everywhere”這一口號的技術基礎:它們為不同的CPU架構提供了不同的“IL轉化器”,僅此而已。與高級語言到IL的轉化類似,CPU也完全不知道自己在執行的指令是從哪里來的,可能是JIT從IL轉化而來,可能是JVM從Java Bytecode轉化而來,也有可能是C語言編譯得來,也有可能是由MIT/GNU Scheme解釋而來。

這就是.NET平臺上的高級語言在機器上運行的第二次轉化:IL =>匯編(機器碼)。

因此,IL和匯編的區別是顯著的。IL擁有各種高級特性,它知道什么是范型,什么是類和方法(以及它們的“名稱”),什么是繼承,什么是字符串,布爾值,什么是User對象。而CPU只知道寄存器,地址,內存,01010101。與匯編相比,IL簡直太高級了,幾乎完全是一個高級語言,比C語言還要高級。因此,您會看到.NET Reflector幾乎可以把IL代碼“一五一十”地反編譯為可讀性良好的C#代碼,包括類,屬性,方法等等;而從匯編只能勉勉強強地反編譯為C語言——而且其中的“方法名”等信息已經完全不可恢復了,更別說“模塊”等高級抽象的內容。您想要把匯編反編譯成C#代碼?相信在將來這是可行的,不過現在這還是天方夜譚。

二、IL并不是萬能的,CLR還有很多內容IL都無法看到

示例一:探究泛型在某些情況下的性能問題

namespace TestConsole

{

public class MyArrayList

{

public MyArrayList(int length)

{

this.m_items = new object[length];

}

private object[] m_items;

public object this[int index]

{

[MethodImpl(MethodImplOptions.NoInlining)]

get

{

return this.m_items[index];

}

[MethodImpl(MethodImplOptions.NoInlining)]

set

{

this.m_items[index] = value;

}

}

}

public class MyList

{

public MyList(int length)

{

this.m_items = new T[length];

}

private T[] m_items;

public T this[int index]

{

[MethodImpl(MethodImplOptions.NoInlining)]

get

{

return this.m_items[index];

}

[MethodImpl(MethodImplOptions.NoInlining)]

set

{

this.m_items[index] = value;

}

}

}

class Program

{

static void Main(string[] args)

{

MyArrayList arrayList = new MyArrayList(1);

arrayList[0] = arrayList[0] ?? new object();

MyList list = new MyList(1);

list[0] = list[0] ?? new object();

Console.WriteLine("Here comes the testing code.");

var a = arrayList[0];

var b = list[0];

Console.ReadLine();

}

}

}

示例目的是證明“.NET中,就算在使用Object作為泛型類型的時候,也不會比直接使用Object類型性能差”。類MyList泛型容器,類MyArrayList直接使用Object類型的容器。在Main方法中將對MyList和MyArrayList的下標索引進行訪問。至此,便出現了一些疑問,為泛型容器使用Object類型,是否比直接使用Object類型性能要差?看MyArrayList.get_Item和MyList.get_Item兩個方法的IL代碼get操作:

// MyArrayList的get_Item方法

.method public hidebysig specialname instance object get_Item(int32 index) cil managed noinlining

{

.maxstack 8

L_0000: ldarg.0

L_0001: ldfld object[] TestConsole.MyArrayList::m_items

L_0006: ldarg.1

L_0007: ldelem.ref

L_0008: ret

}

// MyList的get_Item方法

.method public hidebysig specialname instance !T get_Item(int32 index) cil managed noinlining

{

.maxstack 8

L_0000: ldarg.0

L_0001: ldfld !0[] TestConsole.MyList`1::m_items

L_0006: ldarg.1

L_0007: ldelem.any !T

L_000c: ret

}

這兩個方法的區別只在于紅色的兩句。我們“默認”ldfld指令的功能在兩段代碼中產生的效果完全相同(畢竟是相同的指令嘛),但是您覺得ldelem.ref指令和ldelem.any兩條指令的效果如何,它們是一樣的嗎?我們通過查閱一些資料可以了解到說,ldelem.any的作用是加載一個泛型向量或數組中的元素。不過它的性能如何?您能得出結果說,它就和ldelem.ref指令一樣嗎?

除非您了解到JIT對待這兩個指令的具體方式,否則您是無法得出其中性能高低的。因為IL還是過于高級,您看到了一條IL指令,您可以知道它的作用,但是您還是不知道它最終造成了何種結果。您還是無法證明“Object泛型集合的性能不會低于直接存放Object的非泛型集合”。因此,比較MyArrayList.get_Item方法和MyList.get_Item方法的匯編代碼,最后得出結果是“毫無二致”。由于匯編代碼和機器代碼一一對應,因此觀察匯編代碼就可以完全了解CPU是如何執行這兩個方法的。匯編代碼一模一樣,就意味著CPU對待這兩個方法的方式一模一樣,它們的性能怎么會有不同呢?

結論:.NET的Object泛型容器的性能不會低于直接使用Object的容器,因為CLR在處理Object泛型的時候,會生成與直接使用Object類型時一模一樣的類型,因此性能是不會降低的。但是您是通過學習IL可以了解這些嗎?顯然不是,如果您只是學習了IL,最終還是要“聽別人說”才能知道這些,而即使您不學IL,在“聽別人說”了之后您也了解了這些——同時也不會因為不了解IL而變得“易忘”等等。

同樣道理,IL的call指令和callvirt指令的區別是什么呢?“別人會告訴你”call指令直接就去調用了那個方法,而callvirt還需要去虛方法表里去“尋找”那個真正的方法;“別人可能還會告訴你”,查找虛方法是靠方法表地址加偏移量;《Essential .NET》還會將方法表的實現結構告訴給你,而這些都是IL不會告訴您的。您就算了解再多IL,也不如“別人告訴你”的這些來得重要。您要了解“別人告訴你”的東西,也不需要了解多少IL。

示例二:只有經過調用的方法才能獲得其匯編代碼嗎?

許多資料都告訴我們,在一個方法被第一次調用之前,它是不會被JIT的。也就是說,直到第一次調用時它才會被轉化為機器碼。不過,這個真是這樣嗎?我們還是準備一段簡單的C#代碼:

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/529977.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/529977.shtml
英文地址,請注明出處:http://en.pswp.cn/news/529977.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

java遍歷斐波納契數列_詳解循環、迭代、遞歸、分治(Leet Code 509 斐波那契數列),實際運用...

Multiple solutions of Fibonacci (Python or Java)本章是用英文寫的,作為或想成為一名優秀的攻城獅,習慣閱讀英文文檔將使你受益良多。例如更好的查看最新版的官方文檔、與國外友人交流、等等 其實英文的生詞也并不多,其中90%的英文都在代碼…

java棧內存是先進后出嗎_java堆內存與棧內存區別

棧(stack):是一個先進后出的數據結構,通常用于保存方法(函數)中的參數,局部變量. 在java中,所有基本類型和引用類型都在棧中存儲.棧中數據的生存空間一般在當前scopes內(就是由{...}括起來的區域).棧的優勢是,存取速度比堆要快,僅次于直接位于CPU中的寄存…

主頁面功能的java_6-04-項目實戰-主頁面顯示當前用戶退出功能實現

教程列表:1-01-servlet學習-HTTP協議的概念作用和特點1-02-servlet學習-HTTP協議的交互流程和請求格式和請求方式1-03-servlet學習-HTTP協議的響應格式和常見狀態碼1-04-servlet學習-服務器介紹&tomcat服務器的安裝和驗證1-05-servlet學習-第一個web項目1-06-se…

java 二分查找 排序_java 冒泡排序 二分查找

下面這個程序是先定義一個整型數組,然后將其中的元素反序賦值,再用冒泡排序進行排序以后用二分查找來查找其中是否有某個數,返回值為-1時表示這個數可能小于這個數組的最小值或大小這個數組的最大值,-2表示這個數比這個數組的最小…

php 數組設置為空,PHP數組設置空值

如果沒有數據存在,如何將數組值設置為null?PHP數組設置空值以下是我的PHP陣列和我JSON編碼 -{"title":"Impalz-Marketing","type":"Business Details","version":"1.0","login":…

什么是寫一個java類,Java什么是類?class的相關介紹

本章給大家帶來Java什么是類?class的相關介紹,讓大家了解關于類(class)的一些知識。有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。class Point{constructor(){}toString(){}}console.log(Object.keys(Point.prot…

windows php sqlite,如何在Apache 2.4(Windows 7)上為PHP 5.6.14配置SQLite3?

我在Windows 7上,在Apache 2.4上使用PHP 5.6.14版,我正在嘗試訪問SQLite3數據庫.我正在……致命錯誤:找不到類“SQLite3”在這里你是一個簡單的PHP代碼…$db new SQLite3(phpdb);if ($db) {$db->query("CREATE TABLE dogbreeds (Name VARCHAR(255), MaxAge…

php 國密 簽名,關于php國密SM3簽名算法

推薦:《PHP視頻教程》php國密SM3簽名算法代碼地址github.com/lizhichao/sm安裝composer require lizhichao/one-sm使用require __DIR__ . /vendor/autoload.php; // 字符串簽名 echo OneSmSm3::sign(abc) . PHP_EOL; echo OneSmSm3::sign(str_repeat("adfas哈哈…

matlab狀態方程 傳遞函數 可控性,實驗一matlab系統的傳遞函數和狀態空間表達式的轉換...

實驗一 MATLAB 系統的傳遞函數和狀態空間表達式的轉換一、 實驗目的1、學習多變量系統狀態空間表達式的建立方法;2、通過編程、上機調試,掌握多變量系統狀態空間表達式與傳遞函數之間相互轉換的方法;3、掌握相應的MATLAB 函數。二、 實驗原理…

php里h和h的區別嗎,編碼h264h和h264b有什么區別

區別如下:1、版本H.265是新的編碼協議,也即是H.264的升級版。H.265標準保留H.264原來的某些技術,同時對一些相關的技術加以改進。新技術使用先進的技術用以改善碼流、編碼質量、延時和算法復雜度之間的關系,達到最優化設置。2、儲…

mysql5.1怎么備份,MySQL 5.1升級到MySQL 5.5的步驟

mysql 5.5已經出來有一段時間,性能有明顯提升,特別是對多核CPU的支持與TPS性能的提升。上周博主介紹了linux下編譯安裝mysql 5.5的步驟,安裝不出意外基本沒有問題。不過可能很多朋友和我一樣一直用的是mysql 5.1,現在想把數據庫升…

php file del 方法,php怎么遍歷文件刪除指定字符

php遍歷文件刪除指定字符的實現方法:首先創建一個PHP示例文件;然后通過“function del($getstr){…}”方法刪除指定目錄下所有指定文件中指定字符串即可。本文操作環境:windows7系統、PHP7.1版,DELL G3電腦php實現遍歷目錄并刪除指…

event類型 php,深入解析PHP的Laravel框架中的event事件操作

有時候當我們單純的看 Laravel 手冊的時候會有一些疑惑,比如說系統服務下的授權和事件,這些功能服務的應用場景是什么,其實如果沒有經歷過一定的開發經驗有這些疑惑是很正常的事情,但是當我們在工作中多加思考會發現有時候這些服務…

php 抽象類 靜態方法嗎,php中的抽象類和靜態方法是什么

php中的抽象類是指:在class前加了abstract關鍵字且存在抽象方法的類,它不能被直接實例化;靜態方法是指:被static關鍵字修飾的方法,靜態方法用于操作靜態屬性。抽象類抽象類是指在 class 前加了 abstract 關鍵字且存在抽…

python目錄結構生成庫,使用CMake構建平臺無關的目錄結構

我試圖為我的跨平臺項目創建一個目錄結構,但遇到了一些問題。我已經讓CMake確定了放置庫和可執行文件的適當位置,但這種結構僅適用于Windows。在我的結構如下所示:項目目錄垃圾箱可執行文件圖書館圖書館Python增壓模塊python腳本這在Windows上…

centos 怎樣下載php,centos下怎樣安裝軟件

centos下安裝軟件的方法是:centos安裝軟件的命令1、rpm包的安裝1.安裝一個包# rpm -ivh2.升級一個包# rpm -Uvh3.移走一個包# rpm -e4.安裝參數--force 即使覆蓋屬于其它包的文件也強迫安裝--nodeps 如果該RPM包的安裝依賴其它包,即使其它包沒裝&#xf…

php fpm 安裝配置,php php+fpm安裝配置

sudo apt - get install php5 - cgi php5 - mysql php5 - fpm php5 - curl php5 - gd php5 - idn php - pear php5 - imagick php5 - imap php5 - mcrypt php5 - mhash php5 - ming php5 - pspell php5 - recode php5 - snmp php5 - tidy php5 - xmlrpc php5 - xsl打開 /etc/ph…

php post 微信沙箱,微信支付平臺錯誤:獲取沙箱密鑰失敗,確保交易密鑰是

按官方提示進行獲取沙箱密鑰的時候,久試不爽,總是提示錯誤 :“獲取沙箱密鑰失敗,確保交易密鑰是否正確”。這個純粹是微信平臺挖的坑呀,文檔沒有詳細的進行一些講解,也沒有提示需要key,下面來說…

shell腳本執行oracle刪除表,shell腳本操作oracle刪除表空間、創建表空間、刪除用戶...

oracle下表空間的導出,用戶的刪除,表空間刪除,用戶新建,表空間新建,數據導入的shell使用非oracle用戶執行該腳本參數說名$1:base表空間的用戶名$2:同步表空間的用戶名使用場景測試用&#xff0c…

PHP標題獲取數據庫內容,php – 如何從數據庫獲取項目的標題并將其發送到CodeIgniter中的標題模板...

嘗試這個>型號更改>控制器已更改。在模型中function get_card($card){$query $this->db->query("SELECT * FROM table_name WHERE creditcards $card ");$result $query->result_array();$count count($result); # Newif(empty($count)){ # Newre…