CLR只记不看笔记(一) 有图有迷茫
只记不看笔记:抄书的时候为了快速记忆,会写一份笔记。对我个人而言这份笔记写过就得,很少再看。即使想复习的时候也还是习惯看书。^_^
本文对于任何读者基本没啥作用,所以怕浪费时间的读者尽量去看书吧。
途中画问号的是迷茫指出,敬请各路大神解答。谢谢
少于200字的文章不让发布,加入以下笔记
第一章 CLR 执行模型 1.1 将源代码编译成托管模块 将编译器视为语法检查 和 “正确代码”的分析器。 C# 源代码文件 --> C# 编译器 --> 托管模块(中间语言和元数据) 托管模块是一个标准的32位windows可移植执行体(PE32)文件或是64位windows可移植(PE32+)文件,都需要CLR才能执行。 PE 是 Portable Excutable的简称 原来编译器和CLR是两个概念。 IL是什么? IL是.NET框架中中间语言(Intermediate Language)的缩写。 使用.NET框架提供的编译器可以直接将源程序编译为.exe或.dll文件, 但此时编译出来的程序代码并不是CPU能直接执行的机器代码,而是一种中间语言IL(Intermedate Language)的代码。
托管模块的组成部分 这些是C# 编译器编译出来的 1.PE32(+)头 格式分为 PE32 和PE32+ 两种 PE32 运行在32位或64位系统上,PE32+ 只能运行在64位系统中 文件类型 包括GUI,CUI或DLL 只是IL汇编器编译出来的托管模块 会忽视上面大多数信息。 包含本地CPU代码的模块,这个托管模块头包含了与本地CPU代码有关的信息 2.CLR头 包含使这个模块成为一个托管模块的信息(可由CLR 和一些实用程序进行解释) 信息如:需要的CLR版本,标志,托管模块入口方法(main 方法)的MethodDef元数据标记,以及模块的元数据、资源、强名称、一些标志及其他不太重要的数据项位置/大小 3.元数据 每个托管模块都包含元数据表 元数据表有2个种类型 1,描述源代码中定义的类型和成员 2,描述源代码引用的类型和成员 4.IL(中间语言)代码 编译器编译源代码时生成的代码。在运行时,CLR将IL编译成本地CPU指令 是说的IL编译器吗? 本地代码编译器(native code compiler)是什么东西?归谁管?什么时候用到它 本地代码编译器生成的是面向特定CPU架构(x86,x64或IA64)的代码 相反,每个面向CLR的编译器生成的都是IL的代码 IL代码有时称为托管代码,因为CLR要管理它的执行。 元数据: 包含COM的类型库和接口定义语言文件。注意CLR元数据远比他们完整 事实上,元数据总是嵌入和代码相同的EXE/DLL 文件中。这使元数据和EXL/DLL中代码密不可分 由于编译器同时生成元数据和代码,把他们绑定一起,并嵌入最终生成的托管模块,所以元数据和他描述的IL代码永远不会失去同步。
元数据的用途: 1.VS 智能感知,解析源数据,指出一个类型 提供哪些方法、属性、事件和字段 方法参数 2.CLR的代码验证过程中使用元数据确保代码只执行“类型安全”的操作 3.元数据允许将一个对象的字段序列化到一个内存块中,将其发送给另一台机器,然后反序列化,在远程机器上重建对象的状态。 4.元数据允许垃圾回收器跟踪对象的生存期。垃圾回收期能判断任何对象的类型,并从元数据知道哪个对象中的哪个字段引用了其他对象。
1.2 将托管模块合并成程序集 程序集的概念 是一个或多个模块 资源文件的逻辑性分组。其次 程序集是重用、安全性以及版本控制的最小单元。 托管模块(IL和元数据)资源文件(.JPEG,GIF,HTML) 经过 C# 编译器(CSC.EXE) 编译成 程序集 默认情况下,编译器实际会把生成的托管模块转换成程序集。 程序集 中包含引用的程序集有关的信息。这些信息使程序集能够自描述
1.3 加载公共语言运行时 程序集 可以是EXE或DLL 最终由CLR 管理这些程序集中的代码的执行。 要求安装.net Framework CLR 被记载 需要做的是 1.装了Framework没有 2.版本是否匹配 3.程序集是 PE32还是PE32+还是其他的 运行一个可执行文件时,windows会检查这个EXE文件的头,判断应用程序需要的是32位地址空间还是64位地址空间 PE32头的文件可以再一个32位或64位地址空间中运行。PE32+ 的头文件需要一个64位地址空间。 Windows还会检查头中嵌入的CPU架构确保当前计算机的CPU是符合要求。 windows检查好EXE文件头决定创建32位、64位还是wow64进程之后 会在进程的地址空间中加载MSCorEE.DLL的X86,X64,IA64版本 然后进程的主线程调用MSCorEE.dll中定义的一个方法。这个方法初始化CLR,加载EXE程序集,然后调用其入口方法(main) 随即,托管的应用程序将启动并运行。 如果一个非托管应用程序调用LoadLibrary来加载一个托管程序集,Windows会自动加载并初始化CLR(如果尚未加载的话),以便处理程序集中的代码。当然, 在这种情况下,进程已经启动并运行了,而这可能限制程序集的可用性。 1.4 执行程序集的代码 代码的执行 static void main() {
Console.WriteLine("hello Tom!"); Console.WriteLine("hello Marry!"); } 当公共语言运行时加载后,MSCorEE.dll 初始化CLR,加载main()函数的EXE程序集,然后调用main()方法 main方法执行之前,CLR 会检测出Main的代码所有引用的类型。为main中的所有引用类型定义一个内部数据结构, 本实例中引用了Console类型I,所以CLR会为Console分配一个内部数据结构 在这个内部数据结构中,Console的每个方法都有一个对应的记录项,该记录项指向存放, 记录项中。实际每个记录项都指向包含在CLR内部的一个未文档化的函数,叫做JITCompiler。 当Main()方法首次调用WriteLine方法时,WriteLine方法对应的 JITCompiler函数被调用,JITcompiler函数负责将WriteLine 方法编译成的IL代码 编译成本地CPU指令。本地CPU指令保存到一个动态分配的内存块中,然后,JITCompiler返回CLR为类型 创建的内部数据结构,找到与被调用的方法对应的那一条记录,修改最初对JITCompiler的引用,让他现在指向内存块的地址。 最后,JITCompiler函数跳转到内存块中的代码。这些代码正是WriteLine
1.5 本地代码生成器:NGen.exe 可以将IL代码编译成本地代码(CPU指令) 作用 加快应用程序的启动速度 因为IL代码已经编译成本地代码了,不需要CLR 再用JIT 去编译。 减少应用程序的工作集 如果一个程序集会同时加载到多个进程中,对该程序集运行NGen.exe可减少应用程序的工作集
NGen 生成的文件存在以下问题 1.没有知识产权保护 2.NGen生成的文件可能数去同步 3交叉的执行时性能 不会解析元数据。 1.6 Framework类库 Framework Class Library 简称FCL.FCL 是一组DLL程序集的统称 略