我一直在使用.net开发应用程序已经有一段时间了。但是,我仍然没有 确定CLR如何知道.net应用程序已经启动。是否每个应用程序都有一个CLR实例?我不认为这可能是这种情况,因为只有一个GC管理所有.net应用程序的所有内存。 CLR是否在后台运行?我很困惑。
答案 0 :(得分:43)
有人用C#或.NET“中间语言”或其他托管语言构建.NET应用程序。
该语言的编译器csc.exe(C#)或ilasm.exe(字节码汇编程序)或其中任何一个生成PE可执行文件。 PE可执行文件具有编译器或汇编程序填充的特定结构。这包括:
单击可执行文件,从命令行运行或从Win32 API执行时,Windows loader implementation(在NTDLL.dll中)接管
加载程序代码负责将可执行文件存入内存,根据需要加载动态链接库,将链接库映射到可执行代码可以访问它们的位置,并使用实际地址更新导入地址表。映射库。
一旦准备就绪,加载程序就会跳转到入口点(通过我假设的是一些恶作剧从内核空间切换到用户空间,或者转换到保护模式,因为应用程序在它自己的受保护的32或64中运行位存储空间)。入口点是mscoree.dll - .NET公共对象运行时执行引擎,它刚刚映射到进程内存中。 我已经看到这个DLL被称为.NET启动垫片,它允许在一台机器上存在多个.NET安装。如果您在自己的常规应用程序中嵌入.NET语言,则Mscoree.dll是您将使用的库。
Mscoree.dll查看从PE可执行文件加载的元数据,特别是CLR标头和目标.NET运行时版本。从那以后它可以CorBindToRuntimeEx 2到正确的CLR版本。
CorBindToRuntimeEx加载正确的.NET运行时实现(并返回一个指向COM接口的指针,允许您调用该.NET运行时。此代码从%WINDIR%\ Microsoft.NET \ Framework中的dll加载\ v #####。
我不确定此时是谁,但可能是mscoree shim使用.NET ICLRRuntimeHost接口指针来调用方法来初始化.NET运行时,垃圾收集器,IL解释器,JIT和IHostControl接口(允许.NET解释器与托管进程对话),并最终告诉Interpreter开始执行已编译应用程序的IL代码。
(我学到了很多东西 - 链接背后有很多信息,我当然没有完全了解所有这些!)
答案 1 :(得分:5)
Windows可执行文件是Portable Executables,这种格式为Windows提供加载和运行程序所需的信息。当Windows遇到.NET程序时,它会加载CLR的一个实例,并将程序的执行交给新的CLR实例。每个运行的.NET程序都托管在它自己的CLR实例中。
CLR进程加载IL程序并将其编译为Native Code(JIT),然后执行代码,负责该程序的内存管理和垃圾收集。