【底层】 C++和C#的编译方式差异 / AOT和JIT
什么是EXE文件?
EXE是二进制的、可移植可执行 (PE)的文件,它包含程序的机器代码、资源和元数据。
具体文件结构如下:
-
文件头
描述了该文件的类型、大小、节段(sections)等信息。 -
节段
代码段(.text):包含实际的机器指令(可执行代码)或中间语言IL代码。
数据段(.data):存储静态数据(如全局变量和常量)。
资源段(.rsrc):包含应用程序使用的资源,如图标、菜单等。
重定位信息(.reloc):当程序需要加载到非原始地址时,重定位信息帮助调整代码和数据的位置。 -
导入表和导出表
列出该程序所依赖的其他库(如 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++得到的。

浙公网安备 33010602011771号