【底层】 C++和C#的编译方式差异 / AOT和JIT

什么是EXE文件?

EXE是二进制的、可移植可执行 (PE)的文件,它包含程序的机器代码、资源和元数据。

具体文件结构如下:

  1. 文件头
    描述了该文件的类型、大小、节段(sections)等信息。

  2. 节段
    代码段(.text):包含实际的机器指令(可执行代码)或中间语言IL代码。
    数据段(.data):存储静态数据(如全局变量和常量)。
    资源段(.rsrc):包含应用程序使用的资源,如图标、菜单等。
    重定位信息(.reloc):当程序需要加载到非原始地址时,重定位信息帮助调整代码和数据的位置。

  3. 导入表和导出表
    列出该程序所依赖的其他库(如 DLL),以及使用的具体函数。

AOT和JIT的区别

  • AOT(Ahead of Time):提前编译。在程序运行前就编译成机器码或者中间语言IL,存放到文件系统中。

  • JIT(Just in Time):即时编译。将中间语言IL在运行时编译成机器码。有点像解释,但不完全是。

C#的编译运行方式

(1) 源代码先被编译成中间语言IL,放入.exe文件的代码段中(.text段)中。

(2) exe文件在双击执行的时候,调用CLR(该clr.dll依赖位于.Net Framework文件夹下,见下图),它使用即时编译JIT来将IL动态编译成机器码,执行具体操作。

图片名称

C++的编译运行方式

源代码直接通过编译器编译得到最后的.exe中的机器码,双击直接执行。(整个从源代码到exe的过程中实际还有预处理、汇编、链接,因为我主要是侧重JIT的差异部分展开对比,所以这些步骤省略没有提)

图片名称

为什么C#要多一个即时编译JIT的步骤?

  • 跨平台性:C# 预先编译成 IL 代码,然后只需在相应平台上实现相应的 CLR,就可以跨平台执行。

  • 易于管理:JIT阶段需要由CLR管理执行,它提供垃圾回收、异常处理、线程管理等服务,简化了开发者的工作。

  • 多语言支持:不管语言是什么,如果都编译成 IL,CLR就可以统一调用(CLR只认识IL)。

什么又是Mono和IL2CPP?

Mono

  • 定义: Mono 是一个开源的跨平台 .NET 框架的实现,最初由 Xamarin 开发,旨在允许 C# 程序在多种平台(包括 Windows、Linux 和 macOS)上运行。

  • 功能:提供了 CLR 的某些功能,并实现了 C# 编译器、类库和运行时。

  • 与 CLR 的关系:Mono 实现了 .NET 的一些核心功能,作为一个替代 CLR 的运行时环境,同时支持运行同样的 IL 代码。

IL2CPP

  • 定义: IL2CPP(Intermediate Language To C++)是 Unity 引擎原生的一部分,将 C# 中间语言代码转换为 C++ 代码,然后编译成机器码,适用于各种平台。
  • 功能: 提供更高效的运行时性能和较强的安全性,特别是在移动和游戏开发中。
  • 与 CLR 的关系: IL2CPP 不直接使用 CLR,而是将 IL 转换为 C++ 代码,绕过 CLR 的运行时环境,从而实现更好的性能和跨平台支持。

两者的优缺点和现状

  • (缺)Mono是.Net的一种实现,它会用CLR,也就是会调用JIT,但IOS上不支持JIT。

  • (缺)Mono有版权限制,用不了C#的一些新特性。

  • (缺)Mono虽然跨平台,但是是需要每个平台单独实现了对应CLR,所以有几个平台就得写几种Mono虚拟机,比较费事。

  • (优)Mono构建速度快一些(不是指运行),因为JIT是运行时用到什么才把什么转换成机器码的,CLR中也有一些内存管理的方法,会快很多。

  • (优)IL2CPP把IL变成C++,各个平台本身就是支持C++的。

  • (缺)IL2CPP构建慢一些,因为要提前把所有的代码转换成C++。不过也只是个小问题。

  • (优)IL2CPP运行快,因为最后的机器码是通过C++得到的。

posted @ 2024-08-18 03:21  JimmyZou  阅读(330)  评论(0)    收藏  举报