23.03.05 《CLR via C#》 笔记 1
第一章 CLR的执行模型
CLR 的概念 公共语言运行时(Common Language Runtime) 可由面向CLR的所有编程语言使用 源代码到托管模块 源代码(各种语言的)由编译器生成托管模块(PE文件头+CLR头+元数据+IL(中间语言)代码) 元数据:描述源代码定义的类型和成员;描述源代码引用的类型和成员 托管模块到程序集 程序集 程序集是一个或多个 【模块(IL和元数据)】或【资源文件(图片、网页等)】的逻辑性分组 程序集是重用、安全性以及版本控制的最小单元 程序集是一个或多个文件,文件中包含一个清单(manifest)【数据块】 在CLR中程序集相当于组件 对只有一个托管模块,没有资源文件的程序集,程序集=托管模块(该清单中指出程序集只由一个文件构成) 程序集中还包含与引用的程序集有关的信息(使得CLR在执行程序集的代码时,能找到直接依赖) 程序集文件的形式可能是EXE,也可能是DLL CLR管理程序集中代码的执行 CLR的加载 直接运行EXE 判断文件是32位还是64位 Windows在进程地址空间加载对应版本的MSCorEE.dll 使用MSCorEE.dll中的方法初始化CLR,加载EXE 调用入口方法(Main) 正在运行的进程加载DLL(LoadLibrary) Windows自动加载并初始化CLR(如果当前没有加载CLR的话) CLR处理程序集中的代码 注意,若进程为64位,加载 执行程序集中的代码 IL语言 IL语言是机器语言 IL语言可以访问CLR的所有功能 高级语言可以访问部分CLR的功能 JIT(just-in-time)编译器将IL语言转换成本机CPU指令 (执行Main方法之前)CLR检测代码中引用的所有类型,分配内部数据结构 内部数据结构中,每个类型的每个方法都有对应的entry 将entry都指向JITCompiler (执行Main函数,有方法被调用)JITCompiler被调用(由于entry) JITCompiler在该类的元数据中查找到该方法的IL 验证IL,并翻译成CPU指令,指令保存到动态分配的内存块中 将该方法entry指向对应CPU指令的内存块 跳转到内存块并执行 (继续执行Main函数,有方法被第二次调用)对应内存块被直接调用(跳过了JITCompiler) (程序终止)动态内存块中的所有指令丢弃 性能讨论 二次编译(IL语言->CPU指令)进行过大量性能优化 JIT可检测当前执行环境(CPU),能利用上特定CPU的特殊指令 NGen工具可将IL编译成本机代码并保存到磁盘中 System.Runtime.ProfileOptimization类在程序运行时检查哪些方法被编译,保存在文件中,下次程序初始化时即并发编译这些代码 安全性 IL语言编程成CPU指令时,CLR执行验证过程(检查参数、类型、返回值等) 通过验证托管代码,可确保代码不会不正确的访问内存,干扰到其他进程,所以多个托管应用程序可以在同一个虚拟地址空间中运行(Windows的每个进程都有自己的虚拟地址空间) 使用unsafe关键字,才允许直接操作内存地址,操作地址处的字节 Framework类库是一组DLL程序集的统称,由于类型数量太多,相关类型放到单独的命名空间中,如System 通用类型系统(Common Type System, CTS) 类型由 字段、方法、属性、事件组成 可见和访问性规则有 public(任何程序集任何类)、private(同一类)、family(protected;派生类)、assembly(internal;同一程序集)、family or assmbly(protected assmbly;任何程序集的派生类或同一程序集的任何类)、family and assmbly(C#无;同一程序集中的派生类) 定义类型继承、虚方法、对象生存期等规则 所有类型从System.Object类型继承 公共语言规范(Common Language Specification, CLS) 为了使不同语言生成的程序集在CLR中互相兼容,任何编译器都必须符合的最小功能集叫CLS 每种语言支持的内容都是CLR、CTS的子集,是CLS的超集 CLS定义类的每个成员要么是字段要么是方法(其他诸如构造器、事件、属性、操作符重载等都转化成字段和方法) 托管代码与非托管代码的互操作性 调用DLL中的非托管函数(如C#调用User32.dll中的方法) 创建托管程序集描述非托管程序集,调用这个托管程序集(如C#中可以使用DirectX Com) 托管代码可以更简单的实现程序集,供非托管代码使用(如使用C#创建的shell扩展)
相关内容