CLR学习之初识CLR
一、什么是CLR?
CLR即公共语言运行时(Common Language Runtime,简称CRL),就是微软为.net产品构建的运行环境,与java的JVM类似,通俗的讲就是.net虚拟机。CLR上实际运行的并不是我们通常所用的编程语言(例如C#、VB等),而是一种字节码形态的“中间语言”。这意味着只要能将代码编译成这种特定的“中间语言”(MSIL),任何语言的产品都能运行在CLR上。CLR通常被运行在Windows系统上,但是也有一些非Windows的版本。这意味着.Net也很容易实现“跨平台”。CLR是.net系列产品运行的基础。
二、CLR与.Net Framework 的关系?
.NET框架 (.NET Framework) 是由微软开发,一个致力于敏捷软件开发(Agile software development)、快速应用开发(Rapid application development)、平台无关性和网络透明化的软件开发平台。.NET框架是以一种采用系统虚拟机运行的编程平台,以通用语言运行库(Common Language Runtime)为基础,支持多种语言(C#、VB.NET、C++、Python等)的开发。(维基百科.Net Framework) |
.Net Framework是一个支持多种开发语言的开发平台,然而这种多语言支持的特性是以CLR为基础的。
三、CLR是怎样工作的
CLR基本工作原理如下图所示:
如上图所示,从源代码到可执行程序,CLR主要做了以下几件事情:
1.将源代码编译成托管代码
托管模块(Managed Module)是一个标准的Windows可移植执行体(PE),其主要由四个部分组分组成,即PE32或PE32+头、CLR头、元数据、IL(Intermediate Language,中间语言)。
PE32(32位)或PE32+(64位)头
这里描述了当前托管模块的基本信息,包括运行的Windows版本、文件类型、生成时间等。对于包含本地 CPU代码的模块,这个头包含了与本地 CPU 代码有关的信息。
CLR头
包含使这个模块成为一个托管模块的信息(可由 CLR 和一些实用程序 进行解释)。头中包含了需要的 CLR 版本,一些 flag,托管模块入口方 法(Main 方法)的 MethodDef 元数据 token,以及模块的元数据、资 源、强名称、一些 flag 以及其他不太重要的数据项的位置/大小
元数据
每个托管模块都包含元数据表。主要有两种类型的表:一种类型的表 描述源代码中定义的类型和成员,另一种类型的表描述源代码引用的 类型和成员
IL代码
编译器编译源代码时生成的代码。在运行时, CLR 将 IL 编译成本地 CPU 指令
2.将托管模块合并成程序集
CLR实际不和托管模块工作,它和程序集工作。程序集(Assembly)是一个抽象概念,在CLR的世界里,程序集就相当于“组件”。可以从以下两点对程序集有一个初步的认识:
程序集是一个或多个模块/资源文件的逻辑性分组
程序集是重用、安全性以及版本控制的最小单元
为更好的理解程序集与托管模块的关系,请参考此文章:http://wenku.baidu.com/link?url=N-mICQEkfET-BvRMd1SBdffQdcpOm3cvyfFGbIS3zaRVuKYuq4Jf88JB1bROWuXFe-fE05Yow8Bb0YqO1UpNG0piJEALPh_waqe6tCySspe
3.加载运行时程序
生成的每个程序集既可以是可执行的应用程序,也可以是DLL(其中含有一组由可执行程序使用的类型)。当然,最终是由CLR管理这些程序集中代码的执行。Windows 检查好 EXE 文件头,决定是创建32位还是64 位进程之后,会在进程的地址空间中 加载 MSCorEE.dll 的 x86,x64 或 IA64 版本。如果是 Windows 的 x86 版本,MSCorEE.dll 的 x86 版本在 C:\Windows\System32 目录中。如果是 Windows 的 x64 或 IA64 版本,MSCorEE.dll 的 x86 版本在 C:\Windows\SysWow64 目录中,64 位版本(x64 或者 IA64)则在 C:\Windows\System32 目录中(为了向后 兼容)。然后,进程的主线程调用 MSCorEE.dll 中定义的一个方法。这个方法初始化 CLR,加载 EXE 程序集, 然后调用其入口方法(Main)。随即,托管的应用程序将启动并运行。
4.执行程序集中的代码
到目前为止,源代码已经被编译成二进制的IL并且包含在程序集中,而且被CLR加载。但是,直接执行运算的CPU来说二进制的IL还是太高级了,而且不同的CPU支持的指令集也有所差异。因此,CLR在这里还需要对已经编译好的IL再次编译,针对CPU版本生成可以直接运行的CPU指令,这个过程是由JIT(Just In Time)编译器完成的,可以称作“即时编译”。
当第一次执行某个函数时,MSCorEE.dll 的JITCompiler函数会从程序集的元数据中获取该方法和方法的IL,并且分配一块内存地址,然后将IL编译成的本地代码放入这块内存,然后执行内存中的本地代码。
当再次执行这个函数的时候,由于内存中已经存在JIT编译好的本地代码,因此不需要再次进行JIT过程,可以直接执行内存中的本地代码。 可以预知的结果是,这种情况下应用程序启动后第一次调用某个模块所花费的时间要比以后调用这个模块要稍微多一些。
现在,通过本地代码生成技术,已经可以在编译阶段就根据计算机的的实际环境生成本地代码,这样以来就可以在运行时节省JIT编译的时间,提高程序的启动效率。这看起来是一个不错的功能,但是实际上运用的不是很广泛,主要是有一下限制:
编译时生成的本地代码太过于依赖本地环境,一旦环境有变化 (包括操作系统更新、.Net Framework版本更新、CPU更换等),以前生成的本地代码都不再适用。
编译时生成的本地代码必须要和程序集保持同步。
编译时生成的本地代码不能像运行时JIT编译那样根据运行时的情况对代码进行优化。
注:本文主要参考《CLR via C#》,同时参考了博客:CLR基础之一---认识CLR [《CLR via C#》读书笔记]
CLR学习之初识CLR的更多相关文章
- SSH 框架学习之初识Java中的Action、Dao、Service、Model-收藏
SSH 框架学习之初识Java中的Action.Dao.Service.Model-----------------------------学到就要查,自己动手动脑!!! 基础知识目前不够,有感性 ...
- DotNetty网络通信框架学习之初识Netty
p{ text-align:center; } blockquote > p > span{ text-align:center; font-size: 18px; color: #ff0 ...
- 初识CLR
眨眼间我已经实习了半年时间并且转正了,身份也正式从一个学生转变为一个职场人,这个博客自从开始实习以来就一直没有更新过= =没错,就是我懒癌晚期,不过不行!一切都要开始走向正轨,此博会继续见证我的成长, ...
- 01.由浅入深学习.NET CLR 基础系列之CLR 的执行模型
.Net 从代码生成到执行,这中间的一些列过程是一个有别于其他的新技术新概念,那么这是一个什么样的过程呢,有什么样的机制呢,清楚了这些基本的东西我们做.Net的东西方可心中有数.那么,CLR的执行模型 ...
- CLR_Via_C#学习笔记之CLR的执行模型
1:公共语言运行时(Common Language Runtime,CLR)是一个可由多种编程语言使用的“运行时”.CLR的核心功能(比如内存管理.程序集加载.安全性.异常处理和线程同步)可由面向CL ...
- SQL CLR学习
SQL CLR (SQL Common Language Runtime) 是自 SQL Server 2005 才出现的新功能,它将.NET Framework中的CLR服务注入到 SQL Serv ...
- 学习笔记:java并发编程学习之初识Concurrent
一.初识Concurrent 第一次看见concurrent的使用是在同事写的一个抽取系统代码里,当时这部分代码没有完成,有许多的问题,另一个同事接手了这部分代码的功能开发,由于他没有多线程开发的经验 ...
- CLR基础之一---认识CLR [《CLR via C#》读书笔记]
<CLR via C#>读书笔记 什么是CLR CLR的基本概念 通用语言运行平台(Common Language Runtime,简称CLR)是微软为他们的.Net虚拟机所选用的名称.这 ...
- 【CLR】详解CLR中的程序集
目录结构: contents structure [+] 程序集的简介 为程序集分配强名称 如何指定程序集的版本资源信息 如何对程序集签名 全局程序集缓存 如何查看程序集的信息 强命名程序集防串改 1 ...
随机推荐
- 并发编程(六)--进程/线程池、协程、gevent第三方库
一.进程/线程池 1.进程池 (1)什么是进程池 如果需要创建的子进程数量不大,可以直接利用multiprocess中的Process来创建.但是当需要创建上百个或上千个,手动创建就较为繁琐,这时就可 ...
- 浅析Volatile关键字
浅析Volatile关键字 在java中线程并发中,线程之间通信方式分为两种:共享内存和消息传递.共享内存指的是多个线程之间共享内存的属性状态:消息传递指的是线程之间发送信息来通信.在介绍volati ...
- boost与MFC的冲突(new)
在MFC对话框程序中用boost::signals2时出现了问题, 由于MFC为了方便调试,在debug下重新定义了new #ifdef _DEBUG#define new DEBUG_NEW#end ...
- Docker Hello-World镜像运行测试
一.命令:docker run hello-world 命令解释:以docker客户端命令的方式运行hello-world镜像 命令运行结果: hadoop@Docker:/opt/docker$ d ...
- 常用dos命令(3)
网络命令 ping 进行网络连接测试.名称解析 ftp 文件传输 net 网络命令集及用户管理 telnet 远程登陆 ipconfig显示.修改TCP/IP设置 msg 给用户发送消息 arp 显示 ...
- Java 构造方法、final
构造方法:构造(创建)对象时使用的方法. 方法名必须与类名称完全相匹配: 构造方法不需要返回类型: 构造方法不能被static.final等关键字修饰,且不能有return返回语句: 伴随着new被调 ...
- 学习:API断点
API的介绍:API(Application Programming Interface,应用程序编程接口)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而 ...
- Scrapy笔记07- 内置服务
Scrapy笔记07- 内置服务 Scrapy使用Python内置的的日志系统来记录事件日志. 日志配置 LOG_ENABLED = true LOG_ENCODING = "utf-8&q ...
- 微信(十一) 使用调试助手申请设备ID和报备流程
以下流程模拟了一个设备,从微信硬件申请一个产品IP,对此ID进行报备生效,查询自己的绑定主人,给绑定主人发送消息的一系列http请求流程. 1 获取微信密钥 下面需要在公众号设备电脑IP白名单的电脑才 ...
- Pandas | 04 Panel 面板
面板(Panel)是3D容器的数据.面板数据一词来源于计量经济学,部分源于名称:Pandas - pan(el)-da(ta)-s. 3轴(axis)这个名称旨在给出描述涉及面板数据的操作的一些语义. ...