你了解.NET 中的 CIL、CLR、JIT 和 CTS吗

作者:微信公众号:【架构师老卢】
11-21 8:31
12

如果你是一名.NET开发人员,可能遇到过诸如CIL、CLR、JIT和CTS这样的术语。这些都是.NET应用程序运行背后的关键概念,理解它们能让你更好地掌握这一框架。

在本文中,我将详细解释这些概念,以便你能了解它们是如何协同工作,从而使.NET应用程序得以运行的。

在阐明这些术语之前,我们先来简要讨论一下程序生命周期的两个不同阶段,在这篇博文中我们会经常提及它们,即运行时和编译时。

运行时和编译时涉及软件开发流程中不同的阶段以及不同的过程。

了解它们是什么以及它们之间的区别,将有助于你更好地理解主要话题。

我们先来了解一下它们:

编译时 编译时是指你编写的源代码(例如用C#编写的)通过编译器被转换为中间形式或机器可读形式的阶段。

编译时在什么时候发生呢? 它发生在你运行程序之前。例如,当你在开发环境中点击“生成”或“编译”按钮时,编译器会检查你的代码是否存在语法错误,并将其转换为可执行格式(如.dll或.exe文件)。

在编译时会发生什么呢?

  • 语法检查:编译器会检查语法错误(例如缺少分号、方法签名不正确等),并报告任何发现的问题。
  • 代码转换:源代码会根据语言的不同,被转换为中间形式(如.NET中的CIL)或机器代码。
  • 类型检查:编译器会确保所有类型(例如变量、方法)都被正确使用。

在编译期间出现的错误被称为编译时错误。例如,如果你在C#中忘记写分号:

int x = 5  // 缺少分号将导致编译时错误

编译器甚至在尝试运行程序之前就会停止并报告这个错误。

运行时 运行时是指你的程序正在积极执行或运行的阶段。此时编译后的代码被加载到内存中,并由运行时环境(例如.NET的CLR)执行。

运行时在什么时候发生呢? 在程序编译完成后,当你实际开始运行它时就进入了运行时阶段。这是程序与用户交互、执行计算、处理数据等的阶段。

在运行时会发生什么呢?

  • 代码执行:你的程序被加载到内存中并由计算机执行。
  • 资源分配:会为变量和对象分配内存,并且程序会与硬件(例如键盘、磁盘、网络)进行交互。

如果程序在运行时遇到错误(例如除以零、空引用等),这些错误被称为运行时错误。

例如,下面这段代码能正确编译,但在执行时会导致运行时错误:

int a = 10;
int b = 0;
Console.WriteLine(a / b);  // 导致运行时错误(除以零)

除以零的问题在编译时不会被捕获,但当你运行程序时,它会崩溃并抛出一个运行时异常。

既然程序生命周期的基础已经介绍完了,让我们来看看每个.NET术语是如何融入这个过程的。

CIL(公共中间语言) 当你编写.NET程序时,你的源代码并不会直接转换为机器代码。相反,它首先会被编译成一种称为CIL(以前称为MSIL——微软中间语言)的中间形式。

CIL是一组低级的、与平台无关的指令集,CLR能够理解它。每一种.NET语言(C#、F#、VB.NET等)都会被编译成这种中间语言。

为什么这很重要呢?

  • 跨语言兼容性:由于所有.NET语言都会编译成相同的中间语言,你可以用不同的语言编写应用程序的不同部分,并且它们能无缝协同工作。
  • 可移植性:CIL使得.NET程序能够在各种平台上运行,因为它不依赖于任何特定的机器/计算机架构。

CLR(公共语言运行时) CLR是运行你的.NET应用程序的引擎。可以把它看作是.NET框架的核心。无论你是用C#、VB.NET还是任何其他.NET支持的语言编写代码,CLR都负责确保你的应用程序能够平稳运行。

CLR都做些什么呢?

  • 内存管理:它会自动处理内存分配和垃圾回收,所以你无需担心清理未使用的内存。
  • 异常处理:它管理程序执行过程中出现的错误,确保这些错误能被捕获并处理。
  • 安全性:它执行安全策略,确保你的应用程序只能执行被允许执行的操作。
  • 多线程:CLR帮助你同时运行多个操作,这对于创建响应迅速的应用程序很有用。

简而言之,CLR就像是一个管理者,监督着你的.NET应用程序,确保它安全且高效地运行。

JIT(即时编译器) JIT编译器负责将CIL转换为计算机实际能够执行的机器代码。这是即时发生的——因此得名——就在代码执行之前进行转换。

它的工作原理如下:

当你运行一个.NET应用程序时,CLR会将CIL代码传递给JIT编译器。 JIT编译器会将CIL转换为正在运行该应用程序的特定处理器的本地机器代码。 这种转换是动态进行的,所以代码是在即将执行前才被编译。

为什么要使用JIT编译呢?

  • 性能:通过在代码需要执行之前对其进行编译,JIT编译器能够根据运行代码的特定硬件对代码进行优化。
  • 可移植性:由于CIL是与平台无关的,JIT编译器能使其适应在不同的硬件上运行。

CTS(公共类型系统) CTS定义了在.NET环境中数据类型是如何被使用和管理的。它确保所有.NET语言(如C#、VB.NET、F#)对类型有共同的理解,这样它们就能协同工作而不会产生冲突。

例如:

如果你在C#中创建一个int变量,在VB.NET中创建一个Integer变量,CTS会确保它们都代表相同的底层数据类型。

这个公共系统使得用一种语言编写的代码能够轻松地与用另一种语言编写的代码进行交互。

假设在同一个项目中有两种不同的语言:C#和VB.NET。在一个文件中,你用C#写了一个返回整数的方法。在另一个文件中,你用VB.NET写了一个使用该C#方法返回结果的方法。

尽管每种语言中数据类型的叫法不同(C#中的int和VB.NET中的Integer),但CTS确保它们都指向相同的底层类型System.Int32

public class MathOperations
{
    public int GetNumber()
    {
        return 42;
    }
}

在VB.NET中,Integer用于表示数字(32位有符号数),它等同于C#中的int

在这里,VB.NET代码正在调用来自C#类的GetNumber()方法并输出结果。

Public Class MathConsumer
    Public Sub PrintNumber()
        Dim mathOp As New MathOperations()
        Console.WriteLine(mathOp.GetNumber())
    End Sub
End Class

尽管C#中的int和VB.NET中的Integer名称不同,但它们在.NET中都被映射到相同的类型System.Int32。CTS确保这两种语言都明白intInteger是同一回事。它规范了数据类型在.NET语言中的工作方式,使它们能够无缝互操作。

为什么CTS很重要呢?

  • 互操作性:你可以在.NET项目中混合搭配使用各种语言,因为它们都共享相同的类型系统。
  • 一致性:它确保所有.NET语言对数据类型的处理方式保持一致,减少错误和混淆。

** 以下是对这些组件如何协同工作的快速回顾:

  1. 你使用诸如C#之类的.NET语言编写代码。
  2. 你的代码被编译成CIL(公共中间语言)。
  3. CLR(公共语言运行时)管理你的应用程序的执行。
  4. 当应用程序运行时,JIT编译器在执行前将CIL转换为机器代码。
  5. CTS(公共类型系统)通过共享一个公共类型系统,确保不同的.NET语言能够协同工作。

综合起来,这些组件使得.NET成为一个强大且灵活的平台,用于构建能够在不同设备和操作系统上运行的应用程序。

通过理解这些概念,你将对.NET应用程序在幕后是如何构建和执行的有更深入的了解。

相关留言评论
昵称:
邮箱:
阅读排行