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.mzph.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…