CLR 的执行模型
模块/程序集
1.模块
托管模块组成部分
- PE32/PE32+头 : PE 即 Portable Executable 表示可执行文件
- CLR 头 : 包含所需的 CLR 版本,Main 方法入口
- 元数据 : 元数据是一组数据表.其中的一些数据表描述了模块中定义的内容,比如类型或成员。还有一些描述了托管模块引用的内容,比如导入的类型、成员。
- IL 代码
元数据用途
- 用于编译,消除了 C/CPP 时期对头文件的依赖
- VS IntelliSense,VS 读取程序集的元数据,提供代码提示
- 允许垃圾回收器追踪对象的生存期,CLR GC 采用的是 Mark-Sweep 形式,在 mark 阶段,元数据可以提供某一对象的某一字段引用了哪个其他的对象,可以把引用的对象也 mark 一下,防止被 GC 回收
2.程序集
程序集是一个或多个模块/资源 文件的逻辑分组。程序集是重用、安全性、以及版本控制的最小单元。一般认为一个 dll/exe 是一个程序集,但是还可以生成多文件程序集,使用 AL.exe
如何判断是否安装了.NET Framework,只需检查%SystemRoot%\System32\MSCorEE.dll
文件即可
如图,文件说明写出是 .NET Runtime Execution Engine
执行程序集中的代码 JIT
当一个方法第一次执行时,CLR 内部的某个表会为该方法所在类型的所有方法创建一个记录项,对应着一个地址,在 JIT 编译 IL => Native code 时查找 IL 代码,JIT 编译好的 Native Code 存放在内存中,并更新表中的地址,也就是下一次调用该方法时,直接执行的是 Native Code,不用再次经过 JIT 了。这个不用是在一个程序的执行时间内,要是将程序关闭了,再打开还得重来。.NET 都是半解释性性语言。
CTS : 通用类型系统
CLS : 通用语言规范
由于各个语言实现的不尽一致,MS 定义了一个公共语言规范(Common Language Specification)
,它详细定义了一个最小功能集.
例如使用[assembly:CLSCompliant(tue)]
指定此程序集是 CLS 兼容的
1 | public UInt32 Abc() |
以上会得到警告,因为有的语言没有 unsigned int,而 Xyz 和 xyz 方法,是依靠大小写来区分的,像 VB 就不能区分这两个方法.
在 CLS 中,类型的成员要么是一个字段
,要么是一个方法
,像是 C#提供的属性(Property),事件(event)/委托(delegate)/运算符重载 都是 C#编译器提供的,到 IL 层,只有字段和方法.delegate 会变成一个类,这个另说.
程序集生成/打包/部署
csc.exe csharp compiler
hello.cs
1 | class Hello |
csc /out:hello.exe /target:exe hello.cs
- /out 表示 输出文件
- /target 或者 /t 表示输出类型
- exe 表示 CUI,控制台窗口
- winexe GUI 应用程序
- library 生成 dll
- module 生成.netmodule 模块,
/addmodule:
添加 module 引用
- /reference: 或 /r 表示添加引用
csc hello.cs
会生成 hello.exe
/out:hello.exe 和 /t:exe 是默认的
CSC 编译时默认引用 MSCorLib.dll,可以指定/nostdlib
使程序不默认引用这个
响应文件(.rsp)
在 CSC 编译的时候,/r /t /out 命令可以保存在一个文件了,如 MyProj.rsp
1 | csc @MyProj.rsp hello.cs |
还会在 CSC.exe 相同目录中查找一个全局的CSC.rsp
文件,例如我的电脑上是C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.rsp
里面 Reference 了一堆基本的 dll,使用/noconfig
指定编译时忽略这个全局响应文件
使用/r:xxx.dll 来引用一个 dll 时,查找路径为
- 工作目录,当前目录
- CSC.exe 所在目录,MSCorLib.dll 从这个文件获取
- /lib 编译时指定 or LIB 环境变量
将模块合并成程序集
hello.cs
1 | class Hello |
method.cs
1 | public class Method |
执行
1 | csc /t:module method.cs |
结果
生成的 netmodule 文件是一个不包含清单元数据表的 PE 文件,添加到一个程序集后,这个 netmodule 不能删除,删除会抛出 FileNotFoundException
1 | 未经处理的异常: System.IO.FileNotFoundException: 未能加载文件或程序集“method.n |
使用 AL.exe 程序连接器
1 | al.exe /t:library /out:example.dll a.netmodule b.netmodule |
使用
/link[resource]连接资源
/resource 嵌入资源
程序集的私有部署
探测目录
- AppDir\ABC.dll
- AppDir\ABC\ABC.dll
- AppDir\privatePath\ABC.dll
- AppDir\privatepath\ABC\ABC.dll
privatePath 在 app.config 中配置
1 | <configuration> |
强命名程序集
1 | sn -k magicdawn.snk //创建一个snk,包含私钥公钥 |
或者
1 | sn -p magicdawn.snk magicdawn.PublicKey //创建两个,publickey只包含公钥 |