惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

MongoDB | Blog
MongoDB | Blog
Recorded Future
Recorded Future
Jina AI
Jina AI
The Register - Security
The Register - Security
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
月光博客
月光博客
博客园 - 三生石上(FineUI控件)
F
Fortinet All Blogs
人人都是产品经理
人人都是产品经理
S
SegmentFault 最新的问题
Apple Machine Learning Research
Apple Machine Learning Research
L
LangChain Blog
Y
Y Combinator Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
GbyAI
GbyAI
The GitHub Blog
The GitHub Blog
Vercel News
Vercel News
博客园 - 【当耐特】
雷峰网
雷峰网
The Cloudflare Blog
阮一峰的网络日志
阮一峰的网络日志
aimingoo的专栏
aimingoo的专栏
云风的 BLOG
云风的 BLOG
I
InfoQ
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google DeepMind News
Google DeepMind News
Security Latest
Security Latest
有赞技术团队
有赞技术团队
L
Lohrmann on Cybersecurity
P
Proofpoint News Feed
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
The Last Watchdog
The Last Watchdog
P
Privacy & Cybersecurity Law Blog
Scott Helme
Scott Helme
Google Online Security Blog
Google Online Security Blog
WordPress大学
WordPress大学
Hacker News - Newest:
Hacker News - Newest: "LLM"
NISL@THU
NISL@THU
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
B
Blog RSS Feed
Cyberwarzone
Cyberwarzone
K
Kaspersky official blog
F
Full Disclosure
Martin Fowler
Martin Fowler
Spread Privacy
Spread Privacy
D
Docker
C
Cisco Blogs
www.infosecurity-magazine.com
www.infosecurity-magazine.com
H
Hacker News: Front Page

博客园 - 如斯夫

Windows Azure中的Affinity Group .NET内存管理 堆栈和堆 应用程序的装载与运行 字符串匹配算法 – Sunday算法 该怎么教育 COM学习 完成了吗? 技术人员面试流程泳道图 创建型模式 C# 面试题目 单链表中删除重复数据 C# 数据结构 单链表反转 C# 面试算法 人的问题 foreach中的隐式类型转换 C# 点滴 - 枚举 数据库惊魂 没有人能随随便便成功 If you are a new test manager – From google testing blog
.NET程序的运行与内存管理
如斯夫 · 2013-06-14 · via 博客园 - 如斯夫

为什么CLR

在我看来,CLR诞生时,定位就是JVM的竞争者,回顾历史,当MS被Sun要求不能给Windows上的Java实现塞私货的时候,MS必须有一个东西能够与JVM抗衡。因此,CLR诞生的最重要的历史原因是--“市场竞争”。所以,从技术的角度来看,我们探究JVM的诞生,似乎能更好地理解CLR – 与JVM极度类似的平台出现的原因。

那么为什么会诞生JVM呢?

JVM是随着Java语言一起诞生的,当年Sun推广Java的口号就是“Write once, run everywhere”,也即所谓的“跨平台”。为了实现跨平台,Java被编译为bytecode,而不是native code,直到运行时,才通过JIT-Compiler编译为本地代码。也就是说,Java通过给操作系统加了一层JVM,由JVM来解释(JIT编译)首次编译产生的bytecode,从而实现了“跨平台”。(加层是解决问题的万能钥匙)。而由于有了JVM,就是可以实现一些更多的东西,比如说,代码的运行时检查,垃圾回收,多语言支持等等,都是实现了最主要目的时附送的意外之喜。

回到CLR,MS既然不能改Java,那就搞个自己能随便改的东西吧,新的语言C#诞生。为了跟Java区分,MS把运行时称为 CLR,把编译出来的东西称为 IL,当然,MS不会强调它“跨平台”--尽管事实上完全可以-- 就在市场策略上强调CLR的多语言支持。

扯淡完毕。

JIT编译过程

CLR需要在运行时将IL转换为本地机器代码(JIT 编译),那CLR怎么能知道IL中的哪个部分应该转换为什么呢?我们的代码里有:属性,方法,类,字段等等,这些都需要正确的转换才能正确运行。

通常,要实现两个东西之间的转换,可以通过两种方式让来告诉转换器怎么转:

1) 配置

2) 约定

配置和约定有什么不同?

配置:相当于给转换器发了一份手册,手册中写着什么东西应该转换另一个什么东西,怎么转。

举个栗子:

如果你玩过积木,一套积木通常会附带一份说明书,说明书上会写一些积木的堆积方式和完成效果。这里的说明书就是所谓的“配置”,写明了多少堆积方式,就是多少不同的“配置”,你按照这个配置,就可以完成从积木到“宫殿”,“城堡”等的转换。

那什么是约定?

约定:相当于咱说好一个转换规则,每次转换就按照这个转换规则转。

举个栗子:

“你我约定 一争吵很快要喊停
也说好没有秘密彼此很透明”

这里的约定就是: 状态A(争吵) –> 转换规则(喊停) -> 状态B(友好)

配置更灵活;约定更简单

回归主题,CLR采取了“配置”的方式告诉转换器IL的几乎全部信息,比如说这个文件里有哪些类型,每个类型有哪些方法、属性、字段,这些信息都在文件的什么地方存放着,是否已经被转换为本地机器代码了等等,我们把这样的“配置”信息成为“元数据”。而这些“配置”信息就在首次编译的时候与编译出来的IL一起放在了编译后生成的文件里,这个文件的格式与原生代码(比如C/C++)编译出来的文件格式是相同的,我们把具有这种格式的文件称为“PE(Portable Executable)文件”,这样,即使没有安装CLR的操作系统,也可以识别这样的文件。

----------插播:PE文件格式-----------

下面是PE文件的格式示意图

clip_image001

我们从上往下看 ,第一部分和第二部分都是关于DOS的,都是为了兼容DOS而背上的沉重的历史包袱。就像我们党的前核心一样,虽然已经不需要了,还总是要坐在主席台的最前排。还好这个包袱不算太大。紧接着就是PE文件头。PE加载器就是读取这部分来决定如何将文件映射到虚拟内存的。

在这里我们不准备深入每个细节,我们只挑选我们最感兴趣的部分:PE是如何执行起来的。PE文件头里有一项叫: AddressOfEntryPoint,从名字我们就能猜到它的作用,它标识了应用程序的入口点。当PE加载器加载我们的应用程序后,就将这个入口点地址告诉EIP。联想到我们第一部分说到的旅行团,这个地址就是领队的房间号码。

接下来是一些section, 这些section中有一个名字是.text,这个section通常存放的是程序的指令,不过在.NET程序中,它还存放IL和元数据。其他的section也各有用处,此处从略。

-----------插播结束------------

对于.NET 生成的PE文件而言,AddressOfEntryPoint和原生程序是不一样的,它指向了一个函数名为:_CorExeMain,这个函数是mscoree.dll中的一个函数 。换句话说,当一个.NET程序启动的时候,第一件事情就是调用mscoree.dll中的_CorExeMain函数,这个函数接管了接下来的运行过程。这个函数做的事情很简单,它根据我们的.NET程序中的信息和本机安装的.NET Framework版本,选择一个合适文件来执行,比如说在Work station上安装的CLR对应的文件是mscorwks.dll而在服务器上安装的CLR对应的文件时mscorsvr.dll;所以mscoree.dll也被称为shim。

以工作站版本的CLR为例,剩下的事情就是mscorwks.dll将在PE文件中找到元数据和IL,将其编译为本地机器代码,然后执行。