深入探讨 .NET 系列:学习了解 CLR(1. 了解CLR)

注:本系列内容大部分来源于《CLR via C#》这本书以及官方文档,书是第四版,书中.NET Framework版本为4.5。其中包含一些个人理解以及网上搜索的相关内容以及GPT的回复。《CLR Via C#》讲的是.NET Framework版本的CLR,虽然与最新版本的可能有变化,但是依旧很有学习了解的必要。

CLR简介:

公共语言运行时(Common Language Runtime, CLR)是一个可由多种编程语言使用的“运行时”。CLR的核心功能(比如内存管理、程序集加载、安全性、异常处理和线程同步)可由面向CLR的所有语言使用。例如,“运行时” 使用异常来报告错误: 因此,面向它的任何语言都能通过异常来报告错误。另外,“运行时”允许创建线程,所以面向它的任何语言都能创建线程。

事实上,在运行时,CLR根本不关心开发人员用哪一种语言写源代码。这意味着在选择编程语言时,应选择最容易表达自己意图的语言。可用任何编程语言开发代码,只要编译器是面向CLR的。既然如此,不同编程语言的优势何在呢? 事实上,可将编译器视为语法检查器和“正确代码”分析器。它们检查源代码,确定你写的一切都有意义,并输出对你的意图进行描述的代码。不同编程语言允许用不同的语法来开发。不要低估这个选择的价值。

摘自《CLR via C# 》第四页

.NET 提供了一个称为公共语言运行时的运行时环境,它运行代码并提供使开发过程更轻松的服务。

公共语言运行时的功能通过编译器和工具公开,你可以编写利用此托管执行环境的代码。 使用面向运行时的语言编译器开发的代码称为托管代码。 托管代码具有许多优点,例如:跨语言集成、跨语言异常处理、增强的安全性、版本控制和部署支持、简化的组件交互模型、调试和分析服务等。

若要使公共语言运行时能够向托管代码提供服务,语言编译器必须生成一些元数据来描述代码中的类型、成员和引用。 元数据与代码一起存储;每个可加载的公共语言运行时可迁移执行 (PE) 文件都包含元数据。 公共语言运行时使用元数据来完成以下任务:查找和加载类,在内存中安排实例,解析方法调用,生成本机代码,强制安全性,以及设置运行时上下文边界。

公共语言运行时自动处理对象布局并管理对象引用,当不再使用对象时释放它们。 按这种方式实现生存期管理的对象称为托管数据。 垃圾回收消除了内存泄漏以及其他一些常见的编程错误。 如果你编写的代码是托管代码,则可以在 .NET 应用程序中使用托管数据、非托管数据或者同时使用这两种数据。 由于语言编译器会提供自己的类型(如基元类型),因此你可能并不总是知道(或需要知道)这些数据是否是托管的。

有了公共语言运行时,就可以很容易地设计出对象能够跨语言交互的组件和应用程序。 也就是说,用不同语言编写的对象可以互相通信,并且它们的行为可以紧密集成。 例如,可以定义一个类,然后使用不同的语言从原始类派生出另一个类或调用原始类的方法。 还可以将一个类的实例传递到用不同的语言编写的另一个类的方法。 这种跨语言集成之所以成为可能,是因为基于公共语言运行时的语言编译器和工具使用由公共语言运行时定义的常规类型系统,而且它们遵循公共语言运行时关于定义新类型以及创建、使用、保持和绑定到类型的规则。

所有托管组件都带有生成它们所基于的组件和资源的信息,这些信息构成了元数据的一部分。 公共语言运行时使用这些信息确保组件或应用程序具有它需要的所有内容的指定版本,这样就使代码不太可能由于某些未满足的依赖项而发生中断。 注册信息和状态数据不再保存在注册表中(因为在注册表中建立和维护这些信息很困难)。 取而代之的是,有关你定义的类型(及其依赖项)的信息作为元数据与代码存储在一起,这样大大降低了组件复制和移除任务的复杂性。

语言编译器和工具公开公共语言运行时的功能的方式对于开发人员来说不仅很有用,而且很直观。 这意味着,公共语言运行时的某些功能可能在一个环境中比在另一个环境中更突出。 你对公共语言运行时的体验取决于所使用的语言编译器或工具。 例如,如果你是一位 Visual Basic 开发人员,你可能会注意到:有了公共语言运行时,Visual Basic 语言的面向对象的功能比以前多了。 运行时提供如下优点:

  1. 性能得到了改进。
  2. 能够轻松使用用其他语言开发的组件。
  3. 类库提供的可扩展类型。
  4. 语言功能,如面向对象的编程的继承、接口和重载。
  5. 允许创建多线程的可缩放应用程序的显式自由线程处理支持。
  6. 结构化异常处理支持。
  7. 自定义特性支持。
  8. 垃圾回收。
  9. 使用委托取代函数指针,从而增强了类型安全和安全性。 有关委派的详细信息,请参阅通用类型系统。

摘自《微软官方文档 / .NET 基础知识 / 执行模型 / 公共语言运行时(CLR)》

注意:
.NET Core 和 .NET 5+ 版本具有一个产品版本,即没有单独的 CLR 版本。
但是,.NET Framework 版本号并非一定要与其包含的 CLR 的版本号相对应。
有关 .NET Framework 版本及其相应 CLR 版本的列表,请参阅 .NET Framework 版本及依赖项。

总结:
CLR,全称Common Language Runtime(公共语言运行时),是.NET Framework的核心组件。它负责管理.NET程序的执行,提供了内存管理程序集加载安全性异常处理线程管理等功能。CLR使得不同编程语言(如C#、VB.NET、F#)编写的代码可以在同一环境下运行,并且可以互操作。

CLR常用术语:

  • IL(Intermediate Language,中间语言):

.NET语言编译后的中间代码,CLR会将IL编译成机器代码执行。

  • JIT(Just-In-Time Compiler,即时编译器):

CLR在运行时将IL代码编译成机器代码的过程称为即时编译(JIT编译)。

  • GC(Garbage Collector,垃圾回收器):

负责自动管理内存,回收不再使用的对象,防止内存泄漏。

  • AppDomain(应用域):

是CLR提供的一个隔离环境,用于在同一进程中运行多个.NET应用程序。

  • CTS(Common Type System,公共类型系统):

定义了.NET支持的所有数据类型及其操作方式,确保不同语言之间的数据类型兼容。

  • CLS(Common Language Specification,通用语言规范):

是一组基础规则,确保不同语言编写的代码可以互操作。

  • FCL(Framework Class Library,框架类库):

是.NET Framework的一部分,提供了丰富的类库,支持各种应用程序的开发。FCL包括基本的系统功能、数据访问、图形界面、网络通信、文件操作等各个方面。

  • 元数据(Metadata):

元数据是用于描述程序集中的类型和成员的信息。它存储在程序集的二进制文件(DLL或EXE)中。元数据的主要功能是提供关于程序结构和内容的信息,这些信息对CLR非常重要,因为CLR依赖元数据来执行各种操作。

  • 托管代码(Managed Code):

托管代码是指由CLR管理的代码。具体来说,它是编译成中间语言(Intermediate Language,IL)并在CLR上运行的代码。托管代码与非托管代码(Unmanaged Code)相对,后者直接编译成机器代码并在操作系统上运行,不受CLR的管理。

托管代码:

使用 .NET 时,我们经常会遇到“托管代码”这个术语。 本文档解释这个术语的含义及其更多相关信息。

简而言之,托管代码就是执行过程交由运行时管理的代码。 在这种情况下,相关的运行时称为公共语言运行时 (CLR),不管使用的是哪种实现(例如 Mono、.NET Framework 或 .NET Core/.NET 5+)。 CLR 负责提取托管代码、将其编译成机器代码,然后执行它。 除此之外,运行时还提供多个重要服务,例如自动内存管理、安全边界、类型安全,等等。

相反,如果运行 C/C++ 程序,则运行的代码也称为“非托管代码”。 在非托管环境中,程序员需要亲自负责处理相当多的事情。 实际的程序在本质上是操作系统 (OS) 载入内存,然后启动的二进制代码。 其他任何工作 - 从内存管理到安全考虑因素 - 对于程序员来说是一个不小的负担。

托管代码是使用可在 .NET 上运行的一种高级语言(例如 C#、Visual Basic、F# 等)编写的。 使用相应的编译器编译以这些语言编写的代码时,无法获得机器代码, 而是获得 中间语言 代码,然后运行时会对其进行编译并将其执行。 C++ 是这条规则的一个例外,因为它也能够生成可在 Windows 上运行的本机非托管二进制代码。

摘自《微软官方文档 / .Net 基础知识 / 高级主题 / 什么是托管代码》

总结:

  1. 托管代码的内存分配和释放由CLR负责,通过垃圾回收机制自动管理内存,减少内存泄漏的风险。
  2. 托管代码在CLR的代码访问安全机制下运行,可以防止未经授权的操作,提高代码的安全性。
  3. 托管代码编译成IL,可以在CLR支持的任何编程语言中互操作。例如,用C#编写的托管代码可以调用由VB.NET编写的托管代码。
  4. CLR提供了统一的异常处理机制,托管代码中的异常可以被捕获和处理,提高代码的稳定性和可靠性。
编译
包含元数据
加载
JIT编译
执行
源代码
中间语言IL
程序集DLL或EXE
CLR
机器代码
操作系统

元数据:

除了生成IL, 面向CLR的每个编译器还要在每个托管模块中生成完整的元数据(metadata)。元数据简单地说就是一个数据表集合。一些数据表描述了模块中定义了什么(比如类型及其成员),另一些描述了模块引用了什么(比如导入的类型及其成员)。元数据是一些老技术的超集。这些老技术包括COM的“类型库”(Type Library)和 “接口定义语言”(InterfaceDefinition Language, IDL)文件。但CLR元数据远比它们全面。另外,和类型库及IDL不同,元数据总是与包含IL代码的文件关联。事实上,元数据总是嵌入和代码相同的EXE/DLL文件中,这使两者密不可分。由于编译器同时生成元数据和代码,把它们绑定一起, 并嵌入最终生成的托管模块,所以元数据和它描述的IL代码永远不会失去同步

元数据有多种用途,下面仅列举一部分。

  • 元数据避免了编译时对原生C/C++头和库文件的需求,因为在实现类型/成员的IL代码文件中,己包含有关引用类型/成员的全部信息。编译器直接从托管模块读取元数据。
  • Microsoft Visual Studio用元数据帮助你写代码。“智能感知”(IntelliSense)技术会解析元数据,告诉你一个类型提供了哪些方法、属性、事件和字段。对于方法,还能告诉你需要的参数。
  • CLR的代码验证过程使用元数据确保代码只执行“类型安全”的操作。
  • 元数据允许将对象的字段序列化到内存块,将其发送给另一台机器,然后反序列化,在远程机器上重建对象状态。
  • 元数据允许垃圾回收器跟踪对象生存期。垃圾回收器能判断任何对象的类型,并从元数据知道那个对象中的哪些字段引用了其他对象。

摘自《CLR via C# 》第五页

总结:
元数据(Metadata)是一种描述性数据,用于描述程序集(Assembly)中的类型成员的信息。在.NET Framework中,元数据是由CLR使用的关键组成部分之一。

作用:

  • 描述程序结构:元数据记录了程序集中定义的所有类型(如类、结构体、接口)及其成员(如字段、方法、属性)的结构信息
  • 存储类型信息:每个类型的完整名称、继承关系、成员的名称、类型、修饰符等信息都存储在元数据中。
  • 支持反射:CLR通过元数据来实现反射(Reflection),允许在运行时动态获取和操作类型信息、调用方法和访问属性等。
  • 程序集的验证和加载:CLR使用元数据来验证程序集的完整性安全性,确保程序集可以被安全加载和执行。
  • 支持跨语言互操作性:元数据定义了一种通用的类型系统(Common Type System,CTS),确保不同语言编写的代码可以互操作。
  • 特性和自定义信息:元数据允许开发者添加自定义特性(Attributes),为类型、成员或程序集添加额外的描述信息和元数据。

元数据的存储和使用:

  • 存储:元数据存储在每个.NET程序集的头部,作为程序集的一部分,与IL代码一起组成程序集文件(DLL或EXE)。
  • 使用方式:CLR在加载程序集时会读取元数据,并根据元数据中的信息来执行各种操作,如类型检查、成员调用和安全性验证等。

下面是使用ILDASM工具(IL反汇编工具)反编译出来的一些元数据截图:
在这里插入图片描述在这里插入图片描述

后续文章将会更深入的解析元数据

程序集:

CLR实际不和模块工作。它和程序集工作。程序集(assembly)是抽象概念,初学者很难把握它的精髓。首先,程序集是一个或多个模块/资源文件的逻辑性分组。其次,程序集是重用、安全性以及版本控制的最小单元。取决于你选择的编译器或工具,既可生成单文件程序集,也可生成多文件程序集。在CLR的世界中,程序集相当于“组件”。

摘自《CLR via C# 》第六页

程序集(Assembly)是.NET Framework中的基本部署单元,它是一组相关的文件,包含了编译后的代码(IL)和相关的元数据。程序集可以是可执行文件(EXE)或动态链接库(DLL),它们在.NET应用程序的开发、部署和执行过程中起着重要作用。

  • 27
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值