深入浅出DOTNET技术原理(二)coreclr和hostfxr剖析

TFM

TFM全称Target Framework Moniker

一般存在于.runtimeconfig.json文件中,用于指定运行时框架。

CLR coreclr和roslyn

CLR全称Common Language Runtime公共语言运行时

CLR是.NET的基座,CLR有多种实现,.NET CORE,.NET FRAMEWORK,MONO

CLR的构成

由核心的几个dll构成,组成一个最小功能集,属于C#世界的根基。

包含coreclr.dll等由C/C++开发的运行时实现(JIT,GC)部分和System.Private.CoreLib.dll托管代码提供的类型系统(Object/String/Array/Type/Exception等)部分。

其他System.开头的dll属于BCL(Base Class Library),在CLR之上构建,相当于语言的标准库(托管库)。

Q: Mircrosoft.开头的dll是什么库?

A: SDK/框架/工具链级别的库,如Microsoft.Extensions.提供了DI依赖注入框架,Logging和Config使用框架。

CLR跨平台能力的由来

CLR是一种解释器,输入是IL中间代码,IL跟平台无关。因此,不同平台上的CLR实现会负责将平台无关的IL语言即时转译成各平台的本地指令代码。

CLR与Roslyn的关系

现在我们知道了CLR接收的是IL代码,而非C#代码。CLR负责运行时,而编译时任务由Roslyn承担。IL作为一种原子级的指令抽象存在,这样又赋予了编译前端多元化的能力。Roslyn除了可以编译C#语言之外,也能编译F#和Visual Basic等Microsoft推出其他语言,C/C++也同样能被编译成IL。(编程语言/高级语言仅作为编译前端)

MSVC编译托管代码命令

bash 复制代码
cl /clr MyClass.cpp /Fe:MyManagedApp.exe
# /clr → 生成托管代码。
# /Fe: → 指定输出文件名。
# 编译后得到的 .exe 或 .dll 可以在 .NET CLR 下运行。

CLR兼容原理

coreclr采用接口和实现相分离的方案来实现多版本运行时库的兼容性。

重点关注dotnet安装路径下packs和shared两个目录:

  1. packs/.../.dll: 仅包含对类型函数的声明,程序在编译时所引用(reference)的dll;

  2. shared/.../.dll: 包含元数据和具体实现,程序在运行时所链接的dll,。

Assembly的构成

Assembly,即托管程序集,载体是PE格式的dll。包含以下数据:

  1. Manifest(程序集清单): 程序集名称,版本号,PublicKey,引用的其他程序集(依赖dll),导出的类型(Exported Types)

  2. Metadata(元数据): Type(类/结构/接口/枚举),方法、属性、字段、事件,方法签名,特性Attributes,泛型信息

  3. IL Code(中间语言):

  4. Resources(资源,可选): 字符串资源,图片,XAML,resx 编译后的内容

Hostfxr

前面讨论了coreclr,主要负责程序运行时的行为,而Hostfxr是coreclr的启动器和调度器。

两种运行模式

1.框架依赖式启动

特性: 由.runtimeconfig.json来指定coreclr运行时,前提需要系统安装好dotnet。
**原理:**hostfxr内部调用hostfxr_initialize_for_runtime_config,传入.runtimeconfig.json进行coreclr初始化工作。

2.独立配置式启动

特性: 生成exe时,与hostfxr,coreclr和依赖库一起打包(自包含发布),运行时无需系统安装dotnet。
**原理:**hostfxr内部调用hostfxr_initialize_for_dotnet_command_line,通过命令行参数自定义初始化行为。

跨语言能力,入嵌式.NET

与.NET FRAMEWORK这种系统内核级框架不同,.NET CORE完全由用户态掌控,这就满足了coreclr能跟其他技术栈混合应用的条件。

通过分离出hostfxr.dll,coreclr.dll和JIT/GC等关键组件,coreclr就可以内嵌入其他语言,作为一个独立/沙盒模块运行。这样,既能发挥原语言的能力,又能借用.NET生态内的功能。

内嵌方案

  1. C/C++使用hostfxr.h和hostfxr.dll来调度coreclr;

  2. Python使用pythonnet模块直接调用coreclr。

最佳实践

**目标:**让其他语言调用托管dll中的功能函数。

  1. 先用hostfxr初始化coreclr;

  2. 然后获取到程序集Assembly中的功能函数,并用coreclr执行;

  3. 宿主语言监管coreclr的异常和执行结果。

函数签名

一般而言,只需知道hostfxr的函数签名,即可对hostfxr.dll中的函数进行调用。hostfxr代码实现位于dotnet/runtime开源项目中,头文件位于https://github.com/dotnet/runtime/blob/main/src/native/corehost/hostfxr.h

若想进一步研究coreclr和hostfxr,可以深入阅读dotnet/runtime的源码。

Standard API

这是早期为了统一.NET FRAMEWORK和.NET CORE两个世界定义的标准基础API规范,为了能构造出同时运行于这两个CLR之上的程序集。

dotnet对Standard API规范的实现,位于netstandard.dll库中。如果你需要开发多CLR兼容的程序集,需要在.csproj的TargetFramework中指定支持的多个框架名称。

NativeAOT

AOT全称Ahead-Of-Time,是指coreclr的超前编译技术。但与其说是技术,倒不如说是对特定平台禁用JIT的妥协。

JIT让coreclr具备了跨平台的能力,AOT又把coreclr打回了原形。

**特性:**coreclr通过JIT运行IL代码,边编译边执行,效率不高(一定程度上)。AOT在编译期直接将部分IL编译成平台二进制,帮助在运行时能提升性能。

**背景:**iOS出于对安全考虑,禁用了内存页的Write/Execute特征,这样就掰断了JIT这对跨平台的翅膀。coreclr在iOS平台,只能通过AOT转为静态编译。

**AOT策略:**如ReadyToRun(R2R)和NativeAOT。这里不做过多介绍,感兴趣可以自行查资料研究。

相关推荐
步步为营DotNet1 天前
深度探索.NET 中ILogger:构建稳健日志系统的核心组件
数据库·.net
黑棠会长1 天前
ABP框架04.复杂业务关系实现(DDD实战)
数据库·c#·.net·ddd·abp
MonkeyBananas1 天前
VS 中创建并安装.NET Framework Windows 服务教程
windows·.net
专注VB编程开发20年2 天前
如何强制ANY CPU的.net程序按32位或64位模式运行?
windows·.net
fs哆哆2 天前
VB.NET函数重载(Overloading)教程(菜菜级)
.net
weixin_421994783 天前
更复杂的结构 - 类与对象
.net·.netcore
云草桑3 天前
C#.net 分布式ID之雪花ID,时钟回拨是什么?怎么解决?
分布式·算法·c#·.net·雪花id