当前位置: 首页 > news >正文

【.Net技术栈梳理】01-核心框架与运行时(CLR)

文章目录

  • 1 .NET Runtime(CLR-公共语言运行时)
    • 1.1 中间语言 IL
      • 1.1.1 从源代码到通用中间语言(IL)
      • 1.1.2 运行时加载:CLR登场
      • 1.1.3 核心步骤:即时编译 (JIT Compilation)
      • 1.1.4 执行与内存管理(GC)
      • 1.1.5 演进与高级模式:分层编译与 AOT

核心框架与运行时是.NET的基石,决定了能开发什么类型的应用已经如何运行。

1 .NET Runtime(CLR-公共语言运行时)

负责执行编译后的代码(中间语言,IL)、内存管理(垃圾回收GC)、异常处理、线程管理等。是所有.Net应用的引擎

1.1 中间语言 IL

.Net运行时(CLR)执行编译后的代码(中间语言,IL)是一个核心过程,理解这个过程就能明白跨平台、安全性、高性能等特性的基础。

整个过程可以概括为一下关键阶段

  1. 编写源代码与编译为IL
  2. 分发与部署(包含IL的程序集)
  3. 运行时加载与即时编译(JIT Compilation)
  4. 执行本地代码
  5. 优化与高级特性(分层编译、AOT)

1.1.1 从源代码到通用中间语言(IL)

当使用 C#、F# 或 VB.NET 编写代码并执行 dotnet build 时,发生的事情与 C/C++ 这样的原生语言完全不同

  • C/C++ (原生编译):编译器直接将源代码编译为针对特定 CPU 架构(如 x86, ARM)和操作系统的本地机器码。这个代码无法在其他平台上运行
  • .NET (托管编译):编译器(如 Roslyn for C#)会将源代码编译为一种称为 中间语言 (IL) 或 通用中间语言 (CIL) 的字节码。同时,它还会生成丰富的元数据(描述代码中的类型、成员、引用等信息)
  • IL是什么

可以把IL想象成一种高度抽象、与特定CPU无关的“汇编语言”。它比高级语言更底层,但是比真正的机器码更高级。它包含了ldloc(加载本地变量)、add(相加)、call(调用方法)这样的指令

  • 为什么这样做?

关键优势:跨平台和语言互操作性。IL是一种统一的、标准的输出格式。无论使用的事C#还是F#,最终都变成了IL。这使得.NET运行时只需要理解IL这一种语言,就能运行所有.NET语言编写的程序。同时,因为IL不是特定于某个平台的,所以同一个IL程序集(.dll或.exe)可以分发到任何有相应.NET运行时(CLR)的平台上(Windows、Linux、macOS)

1.1.2 运行时加载:CLR登场

当运行一个.NET程序时,操作系统会启动.NET运行时(CLR)。CLR的程序集加载器会负责找到并加载程序集(以及它所依赖的所有程序集)。加载后,CLR会读取其中的元数据和IL代码,为执行做准备。

1.1.3 核心步骤:即时编译 (JIT Compilation)

这是最神奇、最核心的一步,CLR不会直接“解释”执行IL(像早期的Java或Python那样)。相反,它使用一个名为JIT编译器(Just-In-Time Compiler)的组件

JIT编译器的工作流程如下:

  1. 按需编译:当一个方法(函数)第一次被调用时,JIT编译器才会开始工作。CLR不会在程序启动时就把所有IL都编译成本地代码,这避免了不必要的启动延迟。
  2. 读取IL:JIT编译器从已加载的程序集中获取该方法的IL代码。
  3. 验证:在编译之前,JIT会执行一个重要的验证过程。它会检查IL代码是否是类型安全的(例如:不会错误地将一个整数当做对象引用来使用)。这个步骤是.NET内存安全和安全沙箱的基石,它能组织大量潜在的内存损坏漏洞。
  4. 编译为本地代码:验证通过后,JIT编译器将IL代码动态地编译成当前所在平台本地机器码(x86、x64、ARM等)。这个过程考虑了当前的CPU和操作系统环境。
  5. 存储和执行:编译生成的本地机器码被存储在内存中的一块特定的区域(通常称为JIT代码堆)。然后CLR修改该方法的方法表,使其条目指向这块新生成的本地代码。最后,程序执行这个刚刚编译好的、极其高效的本地代码。

JIT的优势

  • 跨平台
    同一个IL包,在Windows上JIT编译为x86代码,在Linux上编译为x64代码,在Raspberry Pi上编译为ARM代码。

  • 性能优化
    JIT编译器可以进行运行时优化。它可以根据程序运行的实际环境进行优化。例如,如果它检测到运行程序的CPU支持特定的指令集(如AVX2),它就可以生成使用这些指令的更高效的代码。静态编译器(如C++)在编译时无法知道程序最终会运行在什么CPU上,因此无法做到这一点。

  • 节省内存
    只有真正被执行到的代码才会被编译和加载到内存中。

1.1.4 执行与内存管理(GC)

代码已经是以本地机器码的形式在 CPU 上直接执行了,速度非常快。
在执行过程中,CLR 的另一个核心组件——垃圾回收器 (Garbage Collector, GC)——会持续工作。它负责自动分配和释放内存。当对象不再被引用时,GC 会自动回收它们占用的内存,开发者无需(也不能)手动释放。这消除了内存泄漏和悬空指针等常见问题。

1.1.5 演进与高级模式:分层编译与 AOT

最初的 JIT 编译策略是“一次性编译”,但现代 .NET(.NET Core 3.0+)引入了更先进的策略:

  1. 分层编译 (Tiered Compilation)
  • 第一层 (快速 JIT):当一个方法第一次被调用时,JIT会快速地进行编译,生成优化程度较低但编译速度极快的代码。目标是尽快让程序跑起来
  • 第二层 (优化 JIT):如果发现某个方法被频繁调用(成为“热路径”),CLR会在后台异步地启动一个优化版本的JIT编译器,重新编译该方法,生成高度优化的、更快的本地代码。之后对该方法的调用就会切换到优化版本上。
  • **好处:**完美平衡了启动速度和运行速度。
  1. 预先编译 (AOT - Ahead of Time)
  • 虽然JIT很棒,但是它的编译过程仍然会在程序运行时产生一些开销(CPU和内存)。对于某些场景(如启动速度极致的App、命令工具),我们希望消除这个开销
  • Native AOT:.NET提供了Native AOT编译模式。它在发布时就直接将IL代码编译为本地可执行文件,完全不需要在目标机器上安装.NET运行时,也没有JIT编译阶段
  • 结果:生成的文件更大,启动速度极快,但失去了JIT的运行时优化能力。.NET 8和更高版本对Native AOT的支持已经非常完善

总结与类比

步骤.Net(托管)Java传统原生(C/C++)
编译源代码 -> 中间语言 (IL)+ 元数据源代码 -> 字节码 (.class)源代码 -> 本地机器码 (.exe)
分发包含 IL 的程序集(跨平台)包含字节码的 JAR 文件(跨平台)特定平台的二进制文件
执行CLR + JIT 编译为本地代码并执行JVM + JIT 编译为本地代码并执行操作系统直接加载执行

可以把一个 .NET 程序想象成:

  • IL 是一份标准化的、与烹饪设备无关的菜谱
  • CLR 是一位厨师(JIT 编译器)和一个厨房(运行时环境)
  • 厨师在接到订单(方法调用)时,根据手头的厨具(CPU 架构)和食材(环境),现场(Just-In-Time) 将菜谱翻译成具体的烹饪步骤(本地机器码)并做菜(执行)。

这种方式既保证了菜谱(程序)的通用性,又能让每位厨师(不同平台上的 CLR)利用自己厨房的最优条件做出最好的菜。


文章转载自:

http://h7UTlMtp.qfkdt.cn
http://csFHtmXv.qfkdt.cn
http://bT6lB3U6.qfkdt.cn
http://6wOqCEy5.qfkdt.cn
http://VZ53Kohj.qfkdt.cn
http://Qmt6TNbX.qfkdt.cn
http://OQoE4I5R.qfkdt.cn
http://SdC0VAbI.qfkdt.cn
http://pYSVtMFH.qfkdt.cn
http://syI68mdO.qfkdt.cn
http://g5Nb88dG.qfkdt.cn
http://BIaz7MYD.qfkdt.cn
http://yiG9TFQu.qfkdt.cn
http://ToVmVyMT.qfkdt.cn
http://iNFurNH5.qfkdt.cn
http://Ih3cXuk9.qfkdt.cn
http://D2ePeLSG.qfkdt.cn
http://jKv4XgSy.qfkdt.cn
http://Ya1w0V17.qfkdt.cn
http://HPkYlYqg.qfkdt.cn
http://EOQ2Z2WN.qfkdt.cn
http://ZSxfX649.qfkdt.cn
http://aW2vqypP.qfkdt.cn
http://259ek0LI.qfkdt.cn
http://nxKPcCAl.qfkdt.cn
http://b7RxdpRk.qfkdt.cn
http://2OK54pvz.qfkdt.cn
http://Acnr4qW8.qfkdt.cn
http://74Im5Uvv.qfkdt.cn
http://cNYN82wL.qfkdt.cn
http://www.dtcms.com/a/372426.html

相关文章:

  • 《十字军东征》游戏出现0xc0000022报错的解决办法
  • 个人博客系统_测试报告
  • 第四项修炼:多元权衡——告别“单点最优”,在矛盾中编织和谐
  • Claude 4深度解析:AI编程新王者,双模型重塑行业标杆
  • 个人pytorch安装配置:cuda12.6 python3.13
  • 全栈经验之谈系列:(阶段一)架构思维与全局观
  • 【CMake】变量作用域3——目录作用域
  • 【系统分析师】第10章-关键技术:系统规划与分析(核心总结)
  • PINN驱动的高阶偏微分方程求解MATLAB代码
  • synchronized同步机制
  • 前端实现埋点的方式
  • 免费的GB28181平台,EasyNVR和EasyGBS应该怎么选?
  • ubuntu 24.10 忘记密码进入恢复模式重置密码
  • 缓存无处不在
  • 工具读取分析bmp文件
  • 多线程之HardCodedTarget(type=OssFileClient, name=file, url=http://file)异常
  • HTTP协议​​和​​API设计规范​​
  • 三种傍路设备配置实验
  • 踏脚迈入奇幻乐园
  • torch.dot()向量点乘,向量点乘计算方法, torch.dot如何计算的
  • Java 模块系统深度解析:从 Jigsaw 到现代模块化开发
  • 九联UNT403G/UN413G-内存大小区分参考指南
  • 基于HanLP的地址信息识别:识别出人名、地址和电话号码
  • 【java执行python】
  • 【数据结构】强化训练:从基础到入门到进阶(1)
  • 三.动态规划算法
  • Maya绑定:驱动关键帧动画案例,小球穿过自动门
  • Android影像基础--cameraAPI2核心流程
  • Ollama Python库的使用
  • 【数据结构入门】排序算法(3):了解快速排序