【C#进阶系列】01 CLR的执行模型——一个Hello World的故事
好吧,废话少说,先上一章Hello World图:
我们有了一个Hello world程序,如此之简单,再加上我今天没有用汉字编程o(>﹏<)o,所以一切很简单明了。
故事开始:
编译:
一个程序写完肯定要编译,以前什么C啊什么的都是编译成本机的CPU指令,但是我们的C#不是。
C#,VB.NET都会把它们编译成托管模块,托管模块在一个标准的可移植的PE文件中。(那些懵懂的少年肯定慌了,这是什么鬼,又是托管模块又是PE文件的。莫慌,所有你听不懂的高大上的术语其实都很简单,你现在不需要懂,听我慢慢道来)
所谓PE文件,就是可移植执行体,简单来讲就是.EXE和.DLL这种鬼东西(这个exe和C语言生成的有区别的)。这个PE文件里的托管模块,你可以当做一个对象,对象里有四个属性,一个PE头(描述文件),一个CLR头(描述这个对象的整体的一些信息,比如main入口),元数据(这个很关键,一种元数据表包含源代码中定义的那些那些类型和成员的描述信息,另一种包含引用的类型和成员的描述信息),IL代码(就是你的源代码被编译后的代码,又称中间语言)。
如果觉得麻烦,前面两个属性你可以忘掉了,记住后面两个就好:元数据和IL代码(简单来讲,就是代码的描述信息和编译后的代码)。
但是一个PE文件可不只一个托管模块,它可以由几个托管模块组成。编译器会把多个托管模块和资源文件合并成一个包含清单的程序集,这才是最后的PE文件。
运行:
但是这个托管模块也就是PE文件并不能直接运行,他需要CLR。
CLR常用简写词语,CLR是公共语言运行库(Common Language Runtime)和Java虚拟机一样也是一个运行时环境,它负责资源管理(内存分配和垃圾收集等),并保证应用和底层操作系统之间必要的分离。CLR存在两种不同的翻译名称:公共语言运行库和公共语言运行时。
此描述及以后的描述均来自百度百科,我懒得手打。
CLR的核心功能包括:内存管理,程序集加载,安全性,异常处理和线程同步。
这个东西又称为公共语言运行时。
前面的说到不能直接运行的时候,这里有懵懂的少年肯定说,我生成的exe文件明明可以直接运行。
这是因为你的电脑上安装了.NET Framework。当你在打开exe程序的时候你的进程的主线程会调用MSCorEE.dll的一个方法,这个方法会初始化CLR,再加载exe程序集,然后调用入口方法即main函数。
所以说实际上你的代码运行是需要在CLR上的。
那么CLR到底是怎么玩我们的Hello world的?
它会在运行时编译我们的IL代码。(先别吐槽为什么要编译两次,后面有讲)
早在Main函数执行之前,CLR就会检测Main的代码所引用的所有类型,然后生成了一个内部的数据结构来管理引用类型的访问。
在这个内部结构中,每个类型比如Console的每个方法都会有一个入口,每个入口都有一个地址(这里叫地址A吧),这个地址A就可以找到方法的实现代码。
而在这个内部数据结构初始化的时候,所有的这些入口的地址都会被设置成一个叫JITCompiler的函数。
就比如上面图中的hello world代码第一句,CLR在执行这句代码的时候会跑进JITCompiler这个函数中,这是内部操作:
- 会跑进托管模块,然后根据元数据匹配类名和方法名,获取你要执行的Console这个类里面Writeline这个函数在IL代码里面的地址B。
- 然后编译这段IL代码变成本机的CPU指令放到一块内存空间中,地址为C。(在这个编译之前还会进行验证哦,验证这个IL代码是否安全)
- 接着修改元数据中地址A的值变为地址C的值。
- 最后跳转到地址C开始执行地址C的cpu指令。
那么如果我们第二次去执行Writeline函数呢?此时内部结构中Writeline函数入口的地址指向的已经是编译好的CPU指令的地址了,所以也就不会去执行JITCompiler这个函数。
千万不要认为这样一定会很慢哦,除了第一次运行时JITCompiler的编译可能需要花费掉编译和优化的时间,后来执行的就是本地CPU指令哦。再加上JITCompiler的这个编译会根据你的机器的CPU不同可能会去生成一些专属于本CPU的特殊指令去优化IL代码,有的这种托管程序可能还要比非托管程序快。
好了,本章的精髓就是上面这些了。
现在我们想想为什么要编译两次?
因为这样的话,无论用C#、VB、F#这些东西你都可以生成一样的包含IL代码的托管程序集,然后这个托管程序集在CLR上运行,也就是说可以混合写代码,一个C#代码可以调用VB代码的DLL,用最适合的语言做最适合的事情。
并且在CLR监视之下执行的IL代码因为在执行前会进行安全校验,所以会提高程序的健壮性和可靠性。
【C#进阶系列】01 CLR的执行模型——一个Hello World的故事的更多相关文章
- 01.由浅入深学习.NET CLR 基础系列之CLR 的执行模型
.Net 从代码生成到执行,这中间的一些列过程是一个有别于其他的新技术新概念,那么这是一个什么样的过程呢,有什么样的机制呢,清楚了这些基本的东西我们做.Net的东西方可心中有数.那么,CLR的执行模型 ...
- 01.CLR的执行模型
在非托管的C/C++中,可以进行一些底层的操作 "公共语言运行时"(CLR)是一个可由多种编程语言使用的"运行时" CLR的核心功能包 ...
- C#进阶系列 ---- 《CLR via C#》
[C#进阶系列]30 学习总结 [C#进阶系列]29 混合线程同步构造 [C#进阶系列]28 基元线程同步构造 [C#进阶系列]27 I/O限制的异步操作 [C#进阶系列]26 计算限制的异步操作 ...
- JavaScript进阶系列05,事件的执行时机, 使用addEventListener为元素同时注册多个事件,事件参数
本篇体验JavaScript事件的基本面,包括: ■ 事件必须在页面元素加载之后起效■ 点击事件的一个简单例子■ 为元素注册多个点击事件■ 获取事件参数 ■ 跨浏览器事件处理 □ 事件必须在页面元素加 ...
- JavaScript进阶系列01,函数的声明,函数参数,函数闭包
本篇主要体验JavaScript函数的声明.函数参数以及函数闭包. □ 函数的声明 ※ 声明全局函数 通常这样声明函数: function doSth() { alert("可以在任何时候调 ...
- CLR 的执行模型(2)
第一章 CLR 的执行模型(2) 本篇内容大纲 Framework 类库(Framework Class Library , FCL) 通用类型系统(Common Type System,CTS) 公 ...
- 第一章 CLR 的执行模型
CLR via C# 读书笔记:第一章 CLR 的执行模型(1) 第Ⅰ部分CLR基础.这部分为三章(第一章:CLR的只想能够模型,第二章:生成.打包.部署和管理应用程序及类型,第三章:共享程序集和强命 ...
- [.NET MVC4 入门系列01]Helloworld MVC 4 第一个MVC4程序
[.NET MVC4 入门系列01]Helloworld MVC 4 第一个MVC4程序 一.练习项目: http://www.asp.net/mvc/tutorials/mvc-4/gettin ...
- 第一部分 CLR基础:第1章 CLR的执行模型
1.1将源代码编译成托管模块
随机推荐
- 无法import的原因(ImportError: No module named *****)
python中,每个py文件被称之为模块,每个具有__init__.py文件的目录被称为包.只要模块或者包所在的目录在sys.path中,就可以使用import 模块或import 包来使用. 如果想 ...
- Pro ASP.NET MVC –第五章 使用Razor
Razor是微软在MVC3中引入的视图引擎的名字,在MVC4中对其进行了改进(尽管改动非常小).视图引擎处理ASP.NET内容.寻找指令,典型地用于插入动态数据并输出到浏览器中.微软维持了两个视图引擎 ...
- pecl install imagick
steven@server:/var/www$ sudo pecl install imagickdownloading imagick-2.3.0.tgz ...Starting to downlo ...
- Linux64位服务器编译安装MySQL5.6(CentOS6.4)
首先到MySQL官网下载MySQL最新版(目前是mysql-5.6.12)上传到服务器上,下面说一下详细的安装过程. 安装依赖包,可以在线更新也可以配置本地源(CentOS本地源配置)yum -y i ...
- volley中网络请求
首先使用Volley类创建 RequestQueue queue = Volley.newRequestQueue(this); Making GET Requests final String u ...
- 在Android下运行Linux平台编译的程序
编译时需注意使用 -static 编译选项: 否则会提示运行:/system/bin/sh: ./i2c: No such file or directory
- Android开发在路上:少去踩坑,多走捷径
转自:http://djt.qq.com/article/view/1193 最近一朋友提了几个Android问题让我帮忙写个小分享,我觉得对新人还是挺有帮助的,所以有了这个小分享. 1.目前, ...
- 转 mv 管道符
需求:想列出指定的内容并将其转移到新的目录中 通过使用mv和管道符有几种方法, 1.file=`ls pattern`;mv $file newdir 2.ls pattern|xargs -i mv ...
- C++ 类的静态成员详细讲解(转)
在C++中,静态成员是属于整个类的而不是某个对象,静态成员变量只存储一份供所有对象共用.所以在所有对象中都可以共享它.使用静态成员变量实现多个对象之间的数据共享不会破坏隐藏的原则,保证了安全性还可以节 ...
- 【Xamarin报错】visual studio android 模拟器部署卡住
模拟器启动成功,但是部署一直等待中,没有反应. 1>Starting deploy 5" KitKat (4.4) XXHDPI Phone ...1>Starting emul ...