先粗略看下各自的意义:
- .Net:以下这些技术的统称。是一个平台,而.NET平台有一个实现标准,叫做.Net Standard;
- .Net Framework/.Net Core/Mono:实现了这个标准,其选择的组件不一定相同
- CLR:Common Language Runtime 一个执行引擎,用于进行一类程序(CLI),提供类型系统、垃圾回收、JIT等功能;目前有3个主要实现,分别为coreclr用于.Net Core、desktop clr用于.Net Framework(有了coreclr之后才获得的一个相对”名称)、Mono(没人给其中的runtime部分单独取名)
- CLI:Common Language Infrastructure 一个经标准化组织认证的标准(ECMA-335),定义了CLR的基础功能和其上执行的程序的标准
- IL:Intermediate Language 用于将程序直接输入CLR的格式,包含二进制格式与其对应的文本格式;IL中的任何构造都与CLR内部严格一一对应;因为早期设计预留了自定义特性的空间,所以其版本十余年不曾变化,各种新功能都使用自定义特性来表示
- CoreFX:随CLR一同发行的发行的一组子程序与类型,任何在CLR上运行的程序皆可调用;其中最底层的部分不能完全用IL表示,有些则是对CLR自身功能的调用,而上层可能依赖对底层的假设,因此其版本与CLR的版本是绑定的
- C# :一个编程语言,使用C语系风格;除了IL能直接表示的基本功能外,还提供了一些经过一定封装的功能;每个功能都可能需要假定CoreFX提供了特定的类型来完成;另两个对应的、由第一方支持的编程语言为F#和VB,其功能集和C#不完全一致
- Roslyn:第一方(标准制定者)实现的编译器,Mono也实现了一个(mcs),二者共同遵循C#语言标准
- .Net Standard:在不同的发行之间为CoreFX的公开接口(即使用方法)及行为规定标准,但不关心其具体实现细节,也允许每个发行提供一些额外内容
所以可以总结一下,.net从一个抽象上来说其实是一个理念,即使得多种语言编写的程序能够通过一个通用的runtime运行在不同的操作系统以及硬件平台上。但光有理念不行,还需要实现,我们这里把对于.net里面的某个实现叫做.net platform(比如.net framework就是一个在windows上实现的.net platform,mono则是一个跨平台的.net platform)。一个.net platform想要达成.net的目标,就需要一些组件,比如上图中CLR通用语言运行时,比如FCL基础类库,比如各种语言的编译器,编译器编译出来的东西想要能在CLR中运行,那也需要遵循一定的标准,这就是CLI和CIL,CIL规定了编译输出的规则,而CLI规定了编译器输入语言的规则,只有符合这种标准的语言才能编译成CIL语言运行在CLR中。
好了现在有了CIL和CLR,程序员可以用符合CLI的语言比如C#编写程序了,然后将其编译成CIL,最后在CLR中运行。但是问题来了,程序员开发程序的时候需要用到一些功能以及数据结构,不可能所有的功能细节都自己实现,不然开发成本也太高了,所以就需要提供一些基础类库,方便程序员进行开发,那么需要提供哪些基础类库呢?这也需要一个标准,而.Net Standard就是用于这个目的,它规定了某个.net platform需要提供哪些API给开发者。这样的话加入一个开发者在.net platform A(比如.net framework)上开发了一个项目,然后想迁移到.net platform B(比如Mono)上,那么只要两个platform实现了同一个.net standard那么源代码就无需修改可以直接编译运行。
不过还有一个问题,假如我有一台机器,装了.net platform A(比如.net framework)和.net platform B(比如Mono),那么我在A上编译出来的一个.net程序放到B上可以运行么?理论上应该没问题,毕竟CIL是统一的,虽然一个是A的CLR一个是B的CLR,但是它们都是用来处理CIL程序,就像java代码编译出来既可以运行在JVM上也可以运行在delvik上一样。然而实际上不一定,因为CIL本身也不是一成不变的,它也有自己的版本,看下面这个文档:
https://msdn.microsoft.com/en-us/library/bb822049.aspx
里面的表格详细说明了.net framework和CLR版本之间的关系,从.net framework 2.0到3.5使用的是CLR 2.0,.net framework 4.0以后使用的是CLR 4.0,中间没有CLR 3.0版本。这也就意味着CIL语言本身也在发生变化,面向CLR 4.0编译出来的程序自然是不能运行在CLR 2.0上的。
说那到底什么是.net framework呢?个人理解从抽象角度说.net framework是对.net标准(这个标准具体包括CLI,CIL,.net standard等)在windows平台上的一套实现,具体上说.net framework包含一整套解决方案,包含许多字组件,比如编译器、CLR、FCL等等,其中每个组件都有自己的版本,比如编译器有自己的版本用于适应不同版本的语言,比如.net framework 3.5的编译器只支持到C# 3.0,最新已经到C# 7.0了;每个版本的.net framework提供的FCL也在不断丰富,比如System.LINQ到.net framework 3.5才有;CLR的版本也会不同,之前已经说过了。因此.net framework的版本其实就是其组件版本的一个集合,高版本的.net framework中的每个子组件都进行了一定的版本更新。
随着.NET Core Framework的开发完成,.NET Framework与Mono将基于.NET Core重新构建。.NET Framework将成为.NET Core在Windows上的一个发行版,Mono将成为.NET Core的一个跨平台发行版。
对于Unity中PlayerSetting中的设置 API Compatibility Level,指的是实现的.Net标准
关于Mono和CLR的GC:
1.mono早期使用的是Boehm-Demers-Wiser GC库,后期更新为有分代和多线程能力的SGen库
2.这里需要强调一下,由于历史原因,unity使用版本比较老的mono,然后在其基础上做了很多修改,以及整合外围的一些新功能,导致的结果是无法跟进最新版本的mono,这也是为什么GC还是最老的Boehm-Demers-Wiser库。所以如果想自己尝试整合最新的mono,很可能会搞成一坨坨。
3.然后,还不能忘了il2cpp,这是完全独立的一个runtime,编译成il2cpp就意味着跟mono没有关系了,这时他也有自己的一套GC实现,很不幸依然使用了老旧的Boehm-Demers-Wiser GC。。
4.mono在语法、编译、runtime、库等等层面上确实执行了.net的标准,但是GC的底层实现上至少早期是没有明确规定怎么实现底层的,就算有,mono因为微软不公开代码的原因,当时也不得不自己摸索一套方案,于是也就有了现在跟.net毫无关联的GC实现。
5.最新的Unity已经加入了incremental GC
总结
最后用图总结下:
1. .NetFramework/.Net Core/Mono实现了.Net标准
2. .NetFramework 运行平台为PC,Mono 和 .NetCore是跨平台的。
3. Mono有自身实现的CLR,即MonoVM,最早的GC版本用的是BoehmGC,也就是Unity用的GC
4. 最新的Unity已经加入了incremental GC
5. IL2CPP也借助Mono编译器,Mono编译器生成的IL代码通过IL2CPP转成C++文件,再通过C++的IL2CPP的VM获得跨平台特性
6. IL2CPP用的GC也是BoehmGC,最新的Unity可以用incremental GC
参考资料:
https://www.zhihu.com/question/317261730
https://www.cnblogs.com/w-wfy/p/7450167.html
https://docs.microsoft.com/en-us/visualstudio/cross-platform/unity-scripting-upgrade?view=vs-2019
https://www.cnblogs.com/u3ddjw/p/10909975.html
https://www.cnblogs.com/shanyou/p/4295163.html