• 一文读懂CRL、程序集、托管模块


    一、什么是CLR

    CLR(commond language runtime)全称公共语言运行时(可以直接理解为一种编译运行语言的东西),他是微软.NET framkework下一个类似于Java虚拟机一样运行平台,主要功能包含比如内存管理、程序集加载(稍后解释什么是程序集)、安全性、异常处理等等功能模块。CLR并不只是只支持C#,只要是任何面向CLR编程(意思就是可以转成了CLR可以读取的托管代码)的开发语言比如VB、F#、Python、PHP、C++等等很多语言都可为CLR所运行(现在看了一脸懵逼没有关系,后面把所有概念讲了全部串联起来形成关系结构就容易理解了)。

    二、什么是IL语言、程序集、托管代码、元数据

    1.IL语言

    为什么这么多语言都可以为CLR所运行,因为Microsoft当年在做CLR的时候创造了好几个面向CLR的语言编译器,这些编译器可以将各种语言转成一种叫做IL(Intermediate Language)的中间语言,CLR在运行时真正调用运行的是被编译后的IL代码,因此基于CLR我们做到各种语言混合开发因为他们最后都会被转成IL语言,然后CLR中的JIT编译器再将IL转译成CPU指令来运行,而IL是一种与CPU无关的机器语言,因此可以做到跨平台。
    这里简单贴一段将C#代码反编译成IL语言后的代码看看是什么样(这里用的ILSPY反编译工具):
    C#代码:

    using UnityEngine;
    public class Test : MonoBehaviour
    {
        void Start()
        {
            int varA = 10;
            int varB = 20;
            int varC = varA + varB;
            Debug.Log(varC);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    因为博主平时主要用Unity引擎,这里直接用Unity的方式写的,Start可以相当于Main方法,然后是通过反编译后的IL代码:
    在这里插入图片描述
    这里博主已经写好了注释,IL语言类似于汇编语言,是直接对堆栈进行的操作。

    2.程序集、托管模块

    托管模块是什么,将各种语言通过编译器编译后生成打包生成的东西你就可以理解为托管模块,它主要由四个部分组成:PE32文件、CLR头部信息、元数据、IL代码(托管代码)
    在这里插入图片描述

    下图直接解释了这四者的分别的作用:
    在这里插入图片描述

    程序集简单的说就是对托管模块的又一次打包,一个程序集可以由一个或多个托管模块组成,程序集其实是一种抽象概念,往简单的理解你可以直接说.exe(可执行文件)和.dll(动态链接库)文件就是程序集,但实际上程序集除了包含所需要运行的代码、版本控制信息、引用信息等各种信息以外,通常还会包含代码所引用的各种资源,这些资源通常分布在各种文件夹下。所以往复杂的理解,你可以将这些由里面包含各种资源、托管模块的多个文件统称之为程序集,但程序集永远只有一个入口。

    3.元数据:

    元数据一种有多个表组成的二进制数据文件。它通常由定义表、引用表、清单表这三种组成。
    1.定义表:包含有ModuleDef、TypeDef、MethodDef、FieldDef、ParamDef等等常用表,顾名思义,这些表就是包含了对各种模块、方法、字段的定义
    2.引用表:包含有AssemblyuRef、ModuleRef、TypeRef、MemberRef等等表(还有许多其他表),同理,它们主要是包含对各其他程序集、PE模块、类型、具体类型成员的引用。
    3.清单表:在整个程序集中有一个文件包含着对程序集各个组成部分的名称,这个就是清单表。

    三、简析CLR内部运行机制

    OK,有了上面的概念后从这里我们重新梳理一遍他们的关系。
    从上层C#类开始,一个或者多个C#类通过编译器转换成一个或多个托管模块,托管模块中又包含着主要的IL(托管代码)和元数据,然后一个或者多个托管模块再通过打包转成一个或者多个程序集,程序集再放入CLR中运行。
    在开始运行时,CLR首先会加载并初始化自身,然后加载程序集中的清单表元数据,获取到所有文件的名称,再开始读取程序集的CLR头,找到应用程序入口的方法(也就是C#中的Main)的MethodDefToken,然后通过Token从IL代码文件中找到并让JIT编译成本机代码。在开始JIT编译时,CLR会去检测和查到此方法所引用到的类型和成员,并去它们所定义的程序集中进行加载,如果这个类型是在其他程序集中所定义那么会去加载其他相关的程序集。同理,如果当加载其他程序集时优惠先去加载程序集的清单文件,扫描清单并判断哪个文件中实现了这个类型,然后去加载这个类型。加载完后CLR创造它内部对应的数据结构来表示类型,然后JIT编译器将其转成CPU指令才开始真正执行。
    这里还有一点要注意的是CLR它也有自己的语法,这里CLR中的”类型”在C#中可以理解为”类(class)”,CLR中的”字段”可以理解为C#中的类的成员变量。但基本上CLR它的语法C#有一部分它都是直接支持的,比如Int32、Int64、Single等等基元类型,这些在C#是可以直接使用的。因为在微软当初为所有运行在CLR上的语言定义了一套公共语言规范(Common Language Specification),也就是我们说的CLS,它定义了最小功能集,任何语言的编译器只要支持这个功能集,生成的类型就能在CLR上运行。基于CLS,所以从微软之后才陆陆续续又有一些高校和团队研究出了很多基于CLR其他语言编译器,使得CLR的生态越来越繁荣。
    在这里插入图片描述

  • 相关阅读:
    Java8从入门到精通 笔记
    1688商品详情技术贴:提升点击率和转化率的优化指南
    maven
    〖Python 数据库开发实战 - MySQL篇㉚〗- MySQL 条件函数
    关于list去除引号+报错invalid literal for int() with base 10:
    基础Python教程之pandas使用总结
    Windows 11 Manager v1.1.8 系统优化工具中文便携版
    kafka快速入门
    java计算机毕业设计vue架构云餐厅美食订餐系统MyBatis+系统+LW文档+源码+调试部署
    excel提取某列字符串数据
  • 原文地址:https://blog.csdn.net/qq_37872192/article/details/127738796