作为一种代码指令平台,Microsoft .NET比微软公司先前推出的其他技术平台要来得更为复杂。由于.NET提供了对多种编程语言以及(在理论上说)多重平台的支持,这就需要在传统的两个代 码层添加一个中间代码层。在这里,传统的两层分别是源代码层和编译后的本机代码层。新加的代码层给.NET平台带来了额外的灵活性,不过,反过来却又增加 了系统的复杂性。此外,由于这一新代码层的出现,一连串的新型应用程序部署选项也首次展现在了程序员的面前。

.NET之与众不同:MSIL

在Microsoft .NET框架内,应用程序可以用好多种高级程序语言编写、创建,例如VB.NET、C#乃至COBOL .NET等等都可以编写.NET应用程序。而通过每一种遵守.NET规范的编程语言所编写的程序代码首先都得通过一种初始编译步骤从源代码变成.NET的 公共标准语言:MSIL(微软中介语言:Microsoft Intermediate Language)。MSIL自身是一种完整的、和对象相关的语言,只有它才可能创建出应用程序。为了大致了解MSIL的一些有关情况,你可以参看“通过 MSIL语言了解CLR的运行原理”一文。.NET应用程序是以MSIL的形式出现的,只有在程序执行的时候才通过即时编译器(JIT)被编译为本机代 码。

.NET的编译过程:从源代码到本机指令

只要装载了assembly代码就会进行JIT编译,可见这是一种汇编级的编译(了解更多assembly技术的细节请参看“Assembly—治愈
“DLL地狱”的良方?”一文)。在编译过程中,JIT编译器一旦首次遭遇对象的索引就会装载匹配对象各个方法声明的对应程序。这样,以后调用方法的时候

就会编译其IL,而方法的对应根程序则被方法的编译后代码的地址所取代。这一过程在每次方法被首次调用的时候进行,产生的本机代码则被缓冲以便会话过程中
下次装载assembly代码的时候可以被使用。显然,这样的指令系统相比传统的编译语言需要更大的处理能力,不过其要求也没有你想象的那么高。

在这里必须澄清一个普遍误解的错误概念,那就是不少人认为.NET应用程序是解释型而非编译型的程序。另外,还有这样的常见错误认识:JIT编译的代码存

储在磁盘上并且可以为同一应用程序执行。虽然这样做也不是不可以,但是,你很快就会明白,这可不是缺省的编译方案。应用程序的IL代码实际上在每次应用程
序运行的时候都会被重新编译为本机代码。

两种编译器

事实上,JIT编译器分成两种(经济编译器和普通编译器),而且它们生来也不是平等的。经济JIT编译器代表了运行一个.NET应用程序所需要的最少功
能,它直接用对等的本机代码取代每一条MSIL指令,不进行任何优化从而也带来更少的系统负载。这也意味着它主要应用在内存等资源比较紧张的平台上。

另一方面,普通JIT编译器则是缺省的运行时配置,它会对其产生的代码进行即时优化。这样做无形中给予了.NET超出传统预编译语言的一个优点:预编译语

言只能对其处理的代码将要运行于其上的平台做一番大致的事前估计。JIT编译器可以经过准确调节达到当前运行时状态,结果可以完成一些预编译语言无法完成
的工作:

·更高效地利用和分配CPU寄存器
·在适当的情况下实施低级代码优化,比如常量重叠、拷贝复制、取消范围检查、取消常规副表达式以及方法内联等
·在代码执行期间监控当前的物理和虚拟内存需求从而更高效地利用内存
·产生特定的平台指令以准确、充分地利用实际的处理器模式

.NET编译的结果就是JIT所带来的额外负载要求并没有产生显著的性能损失。

性能选项

这就是说,每次运行应用程序时MSIL就会被JIT编译。记住,这就是常识了,然后,根据以上内容中说明的原理,在开始启动应用程序以及首次使用非核心功能的时候显然会导致低于优化级的系统性能表现。那么你又该采取什么措施把这种负面影响降低到最小呢?

微软公司的对策是为我们提供了一种名为Pre-JIT的编译器(也被称做本机映像生成器:Native Image
Generator,程序名因此是Ngen.exe)。从表面上看,至少它也算是应付任何性能问题的一项治疗手段。Pre-JIT编译器在运行时之前被调
用,在安装时,它会把全部assembly形式的MSIL编译为本机代码。这种本机代码随后存储在全局assembly缓存(Global
Assembly Cache)的某一个特殊部分供以后使用,这样就完全绕过了JIT编译过程。

乍看之下,这样做应该是解决先前的问题了,对客户端代码而言尤其如此。但是,你还记得吗?普通JIT在编译MSIL的时候实施了大量的即时优化操作。而许

多此类的优化操作,尤其是那些牵扯到寄存器和存储器使用的优化,都是由系统的当前需求所驱动的。所以,批量编译assembly代码的举措就会阻止这些优

化的进行从而在实际上产生出运行更慢的最终代码。在你采用这个法子之前,微软的建议是,比照普通编译下的当前条件,把你的JIT和Ngen版本设置为目标
平台上的同一汇编级。

.NET 代码编译过程的更多相关文章

  1. 【转】Java代码编译过程简述

    转载:https://blog.csdn.net/fuzhongmin05/article/details/54880257. 代码编译是由Javac编译器来完成,流程如下图1所示: 图1 Javac ...

  2. java代码编译过程

    简单随笔 java程序需要先编译成class文件然后才能执行,由于是编程成立机器代码,虚拟机加载内存的时候更快的执行. java文件编译成class文件步骤如下: 1)词法分析,检查每一个关键字单词是 ...

  3. ios oc 代码 转换为 c++ 描述代码编译过程

    clang -rewrite-objc main.m #import <Foundation/Foundation.h> #import <objc/runtime.h> // ...

  4. python代码是解释型语言,为什么还有编译过程?

    Python 代码在运行前,会先编译(翻译)成中间代码,每个 .py 文件将被换转成 .pyc 文件,.pyc 就是一种字节码文件,它是与平台无关的中间代码,不管你放在 Windows 还是 Linu ...

  5. 【lombok】使用lombok注解,在代码编写过程中可以调用到get/set方法,但是在编译的时候无法通过,提示找不到get/set方法

    错误如题:使用lombok注解,在代码编写过程中可以调用到get/set方法,但是在编译的时候无法通过,提示找不到get/set方法 报错如下: 解决方法: 1.首先查看你的lombok插件是否下载安 ...

  6. C语言代码区错误以及编译过程

    C语言代码区错误 欲想了解C语言代码段会有如何错误,我们必须首先了解编译器是如何把C语言文本信息编译成为可以执行的机器码的. 背景介绍 测试使用的C语言代码 导入标准库,定义宏变量,定义结构体,重命名 ...

  7. GCC编译过程

    以下是C程序一般的编译过程: gcc的编译流程分为四个步骤,分别为:· 预处理(Pre-Processing) 对C语言进行预处理,生成*.i文件.· 编译(Compiling) 将上一步生成的*.i ...

  8. Linux系统GCC常用命令和GCC编译过程描述

    前言: GCC 原名为 GNU C 语言编译器(GNU C Compiler),因为它原本只能处理 C语言.GCC 很快地扩展,变得可处理 C++.后来又 扩展能够支持更多编程语言,如Fortran. ...

  9. 如何提升代码编译的速度 iOS

    前阵子有遇到代码编译速度慢的问题,特别是在swift和object-c混编的过程中问题很突显. 网上找到一篇蛮好的文章里面又一些解决方法 推荐一下 http://www.open-open.com/l ...

随机推荐

  1. 在VS2010中,引用了同一解决方案的另一个项目的dll,却不能正常调用(转)

    目前发现的原因是,dll的.net 版本比我的程序的高 dll用的.net 4  而程序用的.net 4 client profile 转载源:http://www.cnblogs.com/szyic ...

  2. Python环境的安装

    参考官方文档 http://www.runoob.com/python/python-install.html Python已经被移植在许多平台上(经过改动使它能够工作在不同平台上). 您需要下载适用 ...

  3. VoltDB介绍——本质:数据保存在内存,充分利用CPU,单线程去锁,底层数据结构未知

    转自:http://blog.csdn.net/ransom0512/article/details/50440316 简介 VoltDB数据库是一个分布式,可扩展,shared-nothing的内存 ...

  4. C++调用父类的构造函数规则

    构造方法用来初始化类的对象,与父类的其它成员不同,它不能被子类继承(子类可以继承父类所有的成员变量和成员方法,但不继承父类的构造方法).因此,在创建子类对象时,为了初始化从父类继承来的数据成员,系统需 ...

  5. mysql 无法启动1067

    关键字:mysql无法启动办事,mysql卡死,InnoDB"" registration as a STORAGE ENGINE failed.Unknown/unsupport ...

  6. java 面向对象编程-- 第十三章 反射、类加载与垃圾回收

    1.狭义JavaBean规范 Javabean必须包含一个无参数的public构造方法,方便通过反射的方式产生对象. 属性必须都是私有的. Javabean必须包含符合命名规范的get和set方法,以 ...

  7. 算法导论-钢条切割 C# 递归实现

    下班前看到有位兄弟写 钢条切割问题,尝试实现C#版, 还没有实现最优版,分享一下. int[] parr; private void button1_Click(object sender, Even ...

  8. mybatis中oracle in>1000的处理

    oracle数据库中,如果你使用in,然后括号对应的是一个子查询,当查询出来的结果>1000的时候就会报错. 这个是数据库的规定,我们无法改变它. 如何解决这个问题呢? 现在我看到了三种解决方式 ...

  9. mysql 导入数据库文件到指定数据库

    i:\mysql\bin>mysql  -u  用户名 -p  数据库名  <   i:/test.sql // (source "c:\adsense.sql" ) ...

  10. python3控制路由器--使用requests重启极路由.py

    代码写了相应的注释,以后再写成可以方便调用的模块. 用fiddler抓包可以看到很多HTTP头,经过尝试发现不是都必须的. 'Upgrade-Insecure-Requests':1,#必要项,值为1 ...