初识CLR
眨眼间我已经实习了半年时间并且转正了,身份也正式从一个学生转变为一个职场人,这个博客自从开始实习以来就一直没有更新过= =没错,就是我懒癌晚期,不过不行!一切都要开始走向正轨,此博会继续见证我的成长,从现在开始吧!
最近刚开始看CLR via C#这本神作,本来以为自己会看不懂,之前我对这本书一直是“远观不可亵玩”的态度,当真正看了之后才发现许多事木有有你想象的那么难嘛~好,开始正文。
CLR,又叫通用语言运行时,又叫Common Language Runtime,你可以把他看作是一个虚拟机。来,咱先来看一个很经典的.NET Framework结构图:

我们按照层级关系一层层来看
第一层:
我们最熟悉的编程语言,.NET目前已经支持超过70中编程语言了,只要是.NET支持的编程语言都能享受CLR所带来的便利和优势。
第二层和第三层一起讲:
汇编器,这里的编译器指的不是通常意义的编译器,通常意义指的编译器是指可以直接将高级语言转换成目标机器语言,而这里的汇编器指的是将.NET支持的编程语言编译成托管代码(第三层)。那么问题来了。。。托管代码是什么鬼?可以这么理解,如果说.NET编译器生成的是托管代码,那我们平时学习的C/C++,编译器生成的就是非托管代码。托管代码包含IL和元数据(我擦。。。怎么又多了两个名词),IL指的是微软定义的中间语言(MSIL,Microsoft Intermediate Language,你可以理解为从高级语言到目标机器语言中间的一种代码)。CLR必须知道代码中的数据类型、类和他引用的类型和类的定义才能加载代码、管理内存、执行方法,所以这些信息就叫做metadata。所以第二道第三层的过程就简单的理解为把高级语言编译成中间语言即可。
第四层:
在这一层,CLR提供了运行时非常重要的一个环节即将中间语言编译成目标机器语言的功能。这里我们举个例子再来看一幅图深入讨论一下:

上图展示了一个方法首次调用时发生的事情,在Main方法执行之前,CLR会检测出Main代码所有的引用类型。CLR就会构造像右边那样的一个数据结构,里面是一些方法中用到的引用。这里存着每一个方法的入口,比如Console类中有WriteLine(),WriteLine(string)等,然后CLR会将其进行初始化,将这些入口指向一个未编档函数。这个函数就是JITCompiler。
当Main方法首次调用WriteLine时,JITCompiler会被调用,首先JIT会先申请一块稍后会用到的内存块,然后JITCompiler会在程序集的元数据中找到被调用方法的IL,并将将IL编译成本机的目标代码放入事先分配好的内存当中,接着JIT会修改最初调用它的这个引用指向之前分配好的内存并执行它,最后JIT会回到源代码继续执行下一条语句。这样一来,当Main方法之后再访问这个方法时就会直接去调用本机代码。所以这也是c#到底属于解释型还是编译型语言之争的源头,因为他是在执行的时候才去生成最终的目标代码的。讲到这里,许多人要开始质疑了,托管代码在运行时多了JIT这一步,而非托管代码是直接执行的目标代码,这效率肯定差一大截吧?事实并非如此,微软已经把JIT对性能的影响降到了最低,下面列举了托管代码由于非托管代码的一些地方:
- 当JIT生成本地代码时会根据当前硬件环境去使用当前cpu最优的指令,简单的来说就是根据不同cpu会做代码优化。
- JIT在代码运行时能够检测到代码运行的情况并分析进一步优化代码,比如CLR检测到一个if分支在99%的情况下是true,那么JIT就会重新编译,达到进一步的代码优化。(这一点据说还没有完全实现?有待考证,有知道的可以评论)
嗯。。今天要讲的差不多讲完了


初识CLR的更多相关文章
- CLR学习之初识CLR
一.什么是CLR? CLR即公共语言运行时(Common Language Runtime,简称CRL),就是微软为.net产品构建的运行环境,与java的JVM类似,通俗的讲就是.net虚拟机.CL ...
- Python开发【第一篇】:初识Python
初识python 一.python简介 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆为了在阿姆斯特丹打发时间,决心开发一个新的脚本解 ...
- Python开发【第二篇】:初识Python
Python开发[第二篇]:初识Python Python简介 Python前世今生 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏 ...
- CLR via C#(16)--泛型
泛型就像是一个模板,常常定义一些通用的算法,具体调用时再替换成实际的数据类型,提高了代码的可重用性. 一.初识泛型 1. 简单实例 以最常用的FCL中的泛型List<T >为例: stat ...
- CLR via C#(14)-可空值类型,关于?和??的故事
我们都知道,值类型是不能为Null的,但是在实际应用中有些情形却需要将值类型置为null.因此,CLR中引用了可空值类型的用法.今天的文章中见到最多的符号估计就是?了吧. ?——初识可空值类型 1. ...
- CLR via C# 提纲
第I部分 CLR基础第1章 CLR的执行模型 31.1 将源代码编译成托管模块 31.2 将托管模块合并成程序集 61.3 加载公共语言运行时 81.4 执行程序集的代码 101.4.1 IL和验证 ...
- [CLR via C#]17. 委托
回调函数是一种非常有用的编程机制,它已经存在很多年了.Microsoft .NET Framework通过委托(delegate)来提供一种回调机制.不同于其他平台(比如非托管C++)的回调机 ...
- C#脚本引擎 CS-Script 之(一)——初识
最近在做新产品,这个产品需要满足不同项目对于系统的定制性数据处理需求,比如有的要统计一段时间内某开关打开关闭了多少次,有的要统计一段时间内空调的使用率,有的希望根据温度来控制空调的开还是关,有的则是希 ...
- Python初识与简介【开篇】
目录 1.扯淡 2.Python历史 3.Python简介 4.Python应用 5.为什么是python而不是其他语言? 6.Python的种类 7.Python的特点 8.Python设计哲学 9 ...
随机推荐
- hdoj 1233 还是畅通工程---最小生成树---prime算法
题目:http://acm.hdu.edu.cn/showproblem.php?pid=1233 可以用Kruskal来做,不过当图的边比较稠密的时候用prime会更快一些. AC代码:296MS ...
- DEDE栏目内容调用
{dede:sql sql='Select content from dede_arctype where id=1'} [field:content/] {/dede:sql},
- JavaWeb学习笔记--Listener
JSP中的监听器 Web程序在服务器运行的过程中,程序内部会发生多事件,如Web应用的启动和停止.Session会话的开始和销毁.用户请求的开始和结束等等.有时程序员需要在这些事件发生的时机执行一 ...
- 第一个微信小程序(实现点击一个按钮弹出toast)
今天根据网上的教程搭建了微信小程序的环境,然后看文档做了一个简单的小应用. 项目的目录是这个样子的: app.js.app.json.app.wxss是全局文件,必不可少的文件.定义在app.wxss ...
- 为什么ELF文件的加载地址是0x8048000
在一个进程的虚拟地址空间中,ELF文件是从0x8048000这个地址开始加载的,为什么会是这个地址? 回答:用命令ld --verbose可以看到0x08048000,ld的默认脚本用这个地址作为EL ...
- SaltStack运行任务卡住了,怎么办?
将相关的JOB ID杀死即可. salt-run jobs.active salt "*" saltutil.signal_job JOBID 15
- PYTHON线程知识再研习A
前段时间看完LINUX的线程,同步,信息号之类的知识之后,再在理解PYTHON线程感觉又不一样了. 作一些测试吧. thread:模块提供了基本的线程和锁的支持 threading:提供了更高级别,功 ...
- 关于IoCallDriver
通常我们所知IoCallDriver是把irp传递给下一层设备,传递到底是什么意思呢?IoCallDriver中实际调用了IopfCallDriver,其代码如下:NTSTATUSFORCEINLIN ...
- linux文件合并
第一:两个文件的交集,并集前提条件:每个文件中不得有重复行1. 取出两个文件的并集(重复的行只保留一份)2. 取出两个文件的交集(只留下同时存在于两个文件中的文件)3. 删除交集,留下其他的行1. c ...
- mysql出现错误“ Every derived table must have its own alias”
Every derived table must have its own alias 这句话的意思是说每个派生出来的表都必须有一个自己的别名 一般在多表查询时,会出现此错误. 因为,进行嵌套查询的时 ...