C#系列之:快速了解CLR执行模型

1.1 将源代码编译成托管模块

定义:公共语言运行时(Common Language Runtime,CLR) 描绘:是一个可以由多种编程语言使用的"运行时",其核心功能包括:

  1. 内存管理
  2. 程序集加载
  3. 安全性
  4. 异常处理
  5. 线程同步 这些功能可以由所有面向CLR的语言使用。基于CLR的托管语言和非托管C++语言,在系统层面后者可以进行更低级别的控制,可以完全按照自己的想法管理内存。而CLR不管开发者使用哪一种编程语言写源代码,只要其是面向CLR的。因此,CLR提供了其他技术所无法媲美的集成度,使得混合语言编程成为了开发者可以考虑的一个选项。 为了执行包含托管代码以及托管数据的模块,用户必须在自己的计算机上安装好CLR(目前作为.NET Framework的一部分被提供)

补充:可将编译器是为语法检查其和"正确代码分析器"。

定义:托管模块(managed module) 描述:托管模块是标准的32位(PE32)或者64位(PE32+)的Microsoft Windows可移植体文件,基于CLR来运行。 托管模块四大部分:

  1. PE32 或 PE32+头:如果是依赖于本机CPU的代码,此项会包含和本机CPU相关的信息。
  2. CLR头:包含使这个模块成为托管模块的信息,比如CLR版本,Main方法位置,MethodDef数据,模块元数据等
  3. 元数据:源代码的定义数据,源代码的引用数据
  4. IL代码:编译器编译源代码时生成的代码,运行时CLR将IL编译成编辑CPU代码

定义:托管代码(managed code) 描述:每个面向CLR的编译器生成的代码,都是IL代码(中间代码),IL代码又被称作托管代码。 IL代码比大部分CPU机器语言都更加高级,其可以访问和操作对象的类型,并且提供了指令来创建和初始化对象那个、调用对象上的虚方法以及直接操作数组元素。在此意义上,可以将IL理解成是一种面向对象的机器语言 。 补充:使用高级语言只能使用CLR全部功能当中的一个子集,但IL汇编语言运行开发人员访问CLR全部功能。 逻辑关系:

1.2 将托管模块合并成程序集

定义:程序集(assembly) 描述:CLR实际上并不和托管模块工作,而是和程序集工作。生成的程序集既可以时可执行文件,也可以是DLL,最终由CLR管理这些程序集中的代码的执行。 内容:

  1. 程序集是一个或者多个模块/资源文件的逻辑性分组;
  2. 程序集是重用、安全性以及版本控制的最小单元;
  3. 利用程序集,可以将一组文件作为一个单独的实体来对待; 优势:程序集把文件的逻辑表示和物理表示区分开,利用程序集可以在不同的地方部署文件,在使用到其时再进行下载,不使用其时可以无需下载,但是在对待程序集时确依然将其视为一个整体

逻辑关系:

1.3 加载公共语言运行时

简介 在CLR运行之前,需要设置其平台选项指定最后生成的程序集能够在指定的平台上运行。

CLR运行前设置:设置不同CPU版本 在CLR加载之前,C#编译器提供了一个/platform的命令行选项,允许指定最后生成的程序集能够在指定的平台上运行。 取决于/platform开关选项,C#编译器生成的程序集要么包含PE32,要么是PE32+,在可执行文件运行前,Windows会检查文件头,判断需要的是32位还是64位的地址空间。 之后,Windows检查EXE文件头,决定创建32位或者64位进程,并在进程地址空间加载MSCorEE.dll的x86、x64或者ARM版本。

MSCorEE.dll 进程在Windows当中检查文件头后,需要决定创建32位或者64位进程,之后会在进程的地址空间内加载MSCorEE.dll的对应CPU版本,其不同版本都在%SystemRoot%\System32或者%SystemRoot%\SysWow64目录中。之后进程的主线程调用MSCorEE当中的定义的一个方法,此方法初始化CLR,并加载EXE程序集,调用入口方法Main。

加载CLR

  1. 可执行文件运行前,Windows会检查文件头,判断需要的是32位还是64位的地址空间。
  2. Windows检查EXE文件头,决定创建32位或者64位进程,并在进程地址空间加载MSCorEE.dll的x86、x64或者ARM版本。
  3. 进程的主线程调用MSCorEE.dll中定义的一个方法,此方法初始化CLR,加载EXE程序集,调用其入口方法Main,然后托管应用程序启动并运行。

1.4 执行程序集的代码

定义:即时编译器(Just in time,JIT) 描述:在执行程序集中IL代码的方法后,需要将IL代码转换成本机(native)指令,此时就由CLR当中的JIT编译器来实现。JIT编译器动态的将本机CPU代码存储到动态内存中,因此一旦应用程序停止,编译好的代码也会被丢弃,之后再次启动或者存在两个实例时需要在此编译。

定义:记录项 描述:CLR会分配一个内部的数据结构来管理对引用类型的访问。CLR将引用的类型当中的每个方法都设置一个记录项,这个记录项都含有一个地址,此地址指向该方法的具体实现。当JIT访问记录项,想编译对应函数时,即可顺着此记录项找到对应IL代码。

执行过程

在Main方法执行之前,CLR检测出Main代码引用的所有类型,导致CLR分配一个内部的数据结构来管理对引用类型的访问。CLR将引用的类型当中的每个方法都设置一个记录项, CLR将每个记录项设置为包含在CLR内部的一个未编档函数,此函数为JITCompiler。在调用对应方法时,JITCompiler被调用,查询元数据找到IL代码,并且将此IL代码编译成本机CPU指令。 本机CPU代码动态分配到内存块当中,然后JITCompiler回到CLR为类型创建的内部数据结构,找到被调用方法对应的那条记录,将其修改(原本为对JITCompiler的引用)为指向CPU代码的内存块。第二次验证时,会跳过JITCompiler函数,直接执行内存块当中的代码。因为第二次调用不需要编译,因此只有在首次调用时有一些性能损失。

相关推荐
白茶等风121388 小时前
C#_封装详解
开发语言·c#
friklogff11 小时前
【C#生态园】虚拟现实与增强现实:C#开发库全面评估
c#·ar·vr
VB.Net11 小时前
EmguCV学习笔记 VB.Net 12.1 二维码解析
opencv·计算机视觉·c#·图像·vb.net·二维码·emgucv
虚假程序设计17 小时前
pythonnet python图像 C# .NET图像 互转
开发语言·人工智能·python·opencv·c#·.net
我是苏苏18 小时前
Web开发:ABP框架3——入门级别的接口增删改查实现原理
c#·web开发·abp
Zhen (Evan) Wang18 小时前
.NET 6 API + Dapper + SQL Server 2014
数据库·c#·.net
VB.Net18 小时前
EmguCV学习笔记 VB.Net 12.3 OCR
opencv·计算机视觉·c#·ocr·图像·vb.net·emgucv
俊哥V18 小时前
[备忘]测算.net中对象所占用的内存
c#·.net·内存
闻缺陷则喜何志丹18 小时前
HObject复制耗时试用
c#·指针·halcon·key·图形图形·用时·非安全代码
friklogff19 小时前
【C#生态园】从数据分析到机器学习:掌握C#统计学库的核心功能
机器学习·数据分析·c#