.NET 代码编译过程
作为一种代码指令平台,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 代码编译过程的更多相关文章
- 【转】Java代码编译过程简述
转载:https://blog.csdn.net/fuzhongmin05/article/details/54880257. 代码编译是由Javac编译器来完成,流程如下图1所示: 图1 Javac ...
- java代码编译过程
简单随笔 java程序需要先编译成class文件然后才能执行,由于是编程成立机器代码,虚拟机加载内存的时候更快的执行. java文件编译成class文件步骤如下: 1)词法分析,检查每一个关键字单词是 ...
- ios oc 代码 转换为 c++ 描述代码编译过程
clang -rewrite-objc main.m #import <Foundation/Foundation.h> #import <objc/runtime.h> // ...
- python代码是解释型语言,为什么还有编译过程?
Python 代码在运行前,会先编译(翻译)成中间代码,每个 .py 文件将被换转成 .pyc 文件,.pyc 就是一种字节码文件,它是与平台无关的中间代码,不管你放在 Windows 还是 Linu ...
- 【lombok】使用lombok注解,在代码编写过程中可以调用到get/set方法,但是在编译的时候无法通过,提示找不到get/set方法
错误如题:使用lombok注解,在代码编写过程中可以调用到get/set方法,但是在编译的时候无法通过,提示找不到get/set方法 报错如下: 解决方法: 1.首先查看你的lombok插件是否下载安 ...
- C语言代码区错误以及编译过程
C语言代码区错误 欲想了解C语言代码段会有如何错误,我们必须首先了解编译器是如何把C语言文本信息编译成为可以执行的机器码的. 背景介绍 测试使用的C语言代码 导入标准库,定义宏变量,定义结构体,重命名 ...
- GCC编译过程
以下是C程序一般的编译过程: gcc的编译流程分为四个步骤,分别为:· 预处理(Pre-Processing) 对C语言进行预处理,生成*.i文件.· 编译(Compiling) 将上一步生成的*.i ...
- Linux系统GCC常用命令和GCC编译过程描述
前言: GCC 原名为 GNU C 语言编译器(GNU C Compiler),因为它原本只能处理 C语言.GCC 很快地扩展,变得可处理 C++.后来又 扩展能够支持更多编程语言,如Fortran. ...
- 如何提升代码编译的速度 iOS
前阵子有遇到代码编译速度慢的问题,特别是在swift和object-c混编的过程中问题很突显. 网上找到一篇蛮好的文章里面又一些解决方法 推荐一下 http://www.open-open.com/l ...
随机推荐
- 推荐cms
推荐cms : 国外:drupal joomla wordpress 国内:phpcms
- Google Chrome 源码下载地址 (Google Chrome Source Code Download)
1. Google Chrome 源码 SVN 地址:http://src.chromium.org/svn.包含有 Chrome.Gears.Webkit.GCC 等源码以及编译依赖工具.Chrom ...
- POJ 2159 Ancient Cipher 难度:0
题目链接:http://poj.org/problem?id=2159 #include <cstring> #include <cstdio> #include <cc ...
- visual studio 2013连接Oracle 11g并获取数据:(一:环境搭建)
C# WinForm案例: 目标: visual studio 中点击按钮,就可获取到Oracle中数据表的内容 1.安装Visual Studio 2013 ,推荐如下网址,下载ISO镜像,一路ne ...
- php 判断是否 是手机访问
//判断是否属手机 function is_mobile() { $user_agent = $_SERVER['HTTP_USER_AGENT']; $mobile_agents = Array(& ...
- java调用c++生成的动态和静态库时遇到的问题
java.lang.UnsatisfiedLinkError: no jacob in java.library.path -Djava.library.path 关于java用jni调用 dll动态 ...
- Python标准库---子进程 (subprocess包)
这里的内容以Linux进程基础和Linux文本流为基础.subprocess包主要功能是执行外部的命令和程序.比如说,我需要使用wget下载文件.我在Python中调用wget程序.从这个意义上来说, ...
- JAVA中StringBuffer类常用方法详解
String是不变类,用String修改字符串会新建一个String对象,如果频繁的修改,将会产生很多的String对象,开销很大.因此java提供了一个StringBuffer类,这个类在修改字符串 ...
- 进制转换器(十进制转n进制)
#include<stdio.h> #include<stdlib.h> #define MAXSIZE 100 /*链栈类型定义*/ typedef struct node ...
- UITextView添加一个placeholder功能
控件UITextField有个placeholder属性,UITextField和UITextView使用方法基本类似,有两个小区别:1.UITextField单行输入,而UITextView可以多行 ...