深入浅出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。这里不做过多介绍,感兴趣可以自行查资料研究。

相关推荐
周杰伦fans10 小时前
AutoCAD .NET 二次开发:深入理解 EntityJig 的工作原理与正确实现
开发语言·.net
William_cl1 天前
【C#/.NET 进阶】ASP.NET 架构与最佳实践:DI 依赖注入(IoC 核心)从入门到避坑
c#·asp.net·.net
武藤一雄1 天前
WPF:MessageBox系统消息框
前端·microsoft·c#·.net·wpf
武藤一雄1 天前
WPF进阶:万字详解WPF如何性能优化
windows·性能优化·c#·.net·wpf·.netcore·鲁棒性
唐青枫2 天前
别再层层传参了!C#.NET AsyncLocal 异步上下文透传实战
c#·.net
小邓的技术笔记2 天前
.NET 10 使用 Microsoft.AspNetCore.OpenApi 实现 API 版本管理
.net
夏霞2 天前
IIS 应用程序池 3 种标识:ApplicationPoolIdentity / LocalSystem / LocalService 权限区别(超清晰)
c#·.net
回忆2012初秋3 天前
Quartz.NET 全面解析与实战指南
.net
我是唐青枫3 天前
C#.NET ThreadLocal 深入解析:线程独享数据、性能收益与实战边界
c#·.net
唐青枫3 天前
别再把增删改查写成一锅粥!C#.NET CQRS 从原理到实战
c#·.net