Mobius 一个运行在 .NET Core 上的 .NET 运行时
導(dǎo)語
一個 .NET 應(yīng)用僅僅只是一塊在 .NET 運(yùn)行時上面運(yùn)行的二進(jìn)制代碼。而 .NET 運(yùn)行時只是一個能執(zhí)行這項任務(wù)的程序。當(dāng)前的 .NET Framework 和 .NET Core 運(yùn)行時采用 C++ 編寫,而 Mobius 是一個使用 C# 重寫的 .NET 運(yùn)行時,重寫包括 JIT 編譯和 GC 等,這些邏輯都將和 C++ 無關(guān)
原文:Mobius – .NET runtime running on .NET Core – TooSlowException
https://tooslowexception.com/mobius-net-runtime-running-on-net-core/
我看到這個有趣的項目的時候就想試試安利一下大家,這個項目特別適合用來了解 GC (Garbage Collector 垃圾收集)和 JIT (Just-In-Time Compiler 即時編譯器)的算法
讓 C# 編寫一個 .NET 運(yùn)行時和編寫一個運(yùn)行在這個運(yùn)行時上的 .NET 應(yīng)用是否有可能呢?換句話是不要 Native 的本機(jī)代碼或 C++ 代碼,所有的代碼都是通過 C# 編寫是否有可能?這看起來是一個無窮的遞歸,用 .NET 寫 .NET 的運(yùn)行時運(yùn)行在 .NET 的運(yùn)行時上。這是不是就是將一個 .NET 運(yùn)行時運(yùn)行在另一個 .NET 運(yùn)行時上?
作者kkokosa決定開始試試水,這就是做 Mobius 運(yùn)行時想法的原因。這個想法聽起來很奇怪,連作者都不抱期望在一個世紀(jì)內(nèi)將這個想法投入使用。不過作者的想法是想要了解如果寫出整個 .NET 運(yùn)行時需要多少的代碼量。同時作者也發(fā)現(xiàn)了其實(shí)這個想法的作用其實(shí)很小,即使想象現(xiàn)在有一個 NuGet 包在安裝完成之后就可以添加到咱的應(yīng)用上,此時的這個包就包含了完整的運(yùn)行時代碼,其實(shí)好像也不能做什么
原理
其實(shí)這個想法在其他的領(lǐng)域也有人嘗試過,最著名的不過是 RVM —— 用 Java 編寫的 JVM 虛擬機(jī)。雖然他需要使用 C 的引導(dǎo)啟動,但是能做到自己托管自己,完全由 Java 運(yùn)行的虛擬機(jī)同時不需要其他的虛擬機(jī)。這看起來非常和作者想象的 Mobius 非常接近
這個想法不止作者一個人在想,其實(shí)也有小伙伴在 Github 上發(fā)布了一個?issus?說能否使用 C# 寫 JIT 和 GC 的邏輯
基于這些考慮,可以看到開發(fā) Mobius 的原因如下:
用于實(shí)驗(yàn)和研究的框架。使用 C# 和 .NET 編寫的運(yùn)行時,咱可以更簡易和快速的了解整個原型,比如對 JIT 或 GC 模塊的更改。咱可以使用熟悉的語言如 F# 等去編寫整個 .NET 的底層
用于學(xué)習(xí)。在寫這個框架或參與開發(fā)的時候,可以從里面學(xué)到很多運(yùn)行時的做法。這也是可以用到很多現(xiàn)代化的 C# 特性的項目,使用更底層的 API 如 Span staclallock Unsafe 等
提升性能。這顯然是很有爭議的一點(diǎn)。在另一個托管的運(yùn)行時上面運(yùn)行另一個運(yùn)行時看起來就和高性能沒有關(guān)聯(lián)。但是如果應(yīng)用是熱啟動,那么意味著此時運(yùn)行的代碼生成質(zhì)量可以依托對CPU的優(yōu)化,可以達(dá)到比本機(jī)代碼更好的性能。使用 C# 開發(fā)理論上可以使用更加穩(wěn)健的優(yōu)化。同樣用 C# 寫 GC 也能有相同的提升
用于玩鬧。對于很多人來說,例如德熙看著這個項目一步步搭建起來是十分有趣的
如上面說的,其實(shí)都不是很強(qiáng)的理由,為什么要用 .NET 去寫 .NET 運(yùn)行時。大多數(shù)情況下,人們會認(rèn)為使用 C++ 開發(fā)和使用 C# 開發(fā)不是對立的,兩者的差別不是很大。作者非常同意這個觀點(diǎn),這就是為什么作者其實(shí)是將這個項目當(dāng)成一個玩具和實(shí)驗(yàn)的項目
先拋開是否有必要做這樣的事情,請讓咱想想這個項目可以如何做
基本設(shè)計原理
首先,要理解的最重要的事情是 Mobius 仍然會將咱的應(yīng)用程序編譯為本地 Native 代碼。以這種方式,最終應(yīng)用程序?qū)⒁?幾乎)本機(jī)代碼速度運(yùn)行。不同之處在于托管的基礎(chǔ)設(shè)施,如 GC 和類型系統(tǒng)、JIT編譯器是作為托管代碼運(yùn)行的。這意味著這些代碼也被 JIT 編譯
如上圖,我們有兩層JIT構(gòu)建的代碼和底層實(shí)際運(yùn)行時的本地 Native 代碼。從圖片看起來中間的這一層 .NET Core 基礎(chǔ)設(shè)施的 Mobius 層是多余的。如果這一層是使用無分配對象的方式寫的,那么不需要任何的 GC 方法。在預(yù)熱之后,對 JIT 的調(diào)用也將會很少。這就允許咱假設(shè)在一個正常運(yùn)行的應(yīng)用程序中,大部分在 Mobius 層的內(nèi)容都是經(jīng)過了 JIT 編譯優(yōu)化完成之后運(yùn)行的,這包括了常用的對 .NET Core 代碼的 JIT 構(gòu)建的代碼,這將十分接近 .NET Core 的原生調(diào)用
從上面的圖看,其實(shí) Mobius 的多余還是很明顯。一個可以想的方法是在兩個運(yùn)行時之間共享基礎(chǔ)設(shè)施
重寫整個類型系統(tǒng)并不是一件很有趣的事情。我們甚至可以考慮在 Mobius 中重用相同的 GC 垃圾回收,所以使用 Mobius 給 .NET 應(yīng)用提供對象將看起來不錯。雖然上面的方法請看起來不錯,但依然存在兩個問題:
這大大減少了 Mobius 框架需要研究的功能。因?yàn)闆]有重新研究一遍 GC 和 JIT 算法,我們將被迫考慮如何合并現(xiàn)有的技術(shù)
在 .NET 運(yùn)行時里面 JIT 和 GC 和類型系統(tǒng)都有比較大的耦合。除了在 Mobius 實(shí)現(xiàn)相同的機(jī)制之外沒有其他方法,將會受限于當(dāng)前的方法
基于這個原因,作者認(rèn)為 .NET Core 運(yùn)行時應(yīng)該只提供很少量的運(yùn)行時服務(wù)給到 Mobius 框架,提供的服務(wù)主要只是調(diào)用 Jit 編譯代碼
當(dāng)前狀態(tài)
當(dāng)前作者還是試驗(yàn)可行性,正在做的是讓最簡單的 C# 應(yīng)用能玩起來
private static int Main(string[] args)?
{
? int num = 1;
? int num2 = 2;
? return num + num2;
}
通過一些可行性的測試,作者看到了曙光,應(yīng)該是能做出來的。目前所有需要的機(jī)制都已就緒,包括:即使編譯的基礎(chǔ)支持,通過托管調(diào)用 JIT 代碼,通過 JIT 代碼調(diào)用 Mobius 框架。但是因?yàn)闇y試可行性的項目代碼寫的糟,還需要一點(diǎn)時間對代碼進(jìn)行重構(gòu),完善并實(shí)現(xiàn)大量的元數(shù)據(jù)處理,去掉一些硬編碼值
現(xiàn)在這個可行性項目只是能做到運(yùn)行當(dāng)前這個簡單的應(yīng)用而已,運(yùn)行的時候通過完全的 CIL 指令和沒有任何的異常處理,同時只有 GC 的存根
在下一篇系列文章中,作者將介紹Mobius實(shí)現(xiàn)最底層部分的更多細(xì)節(jié)和代碼片段
逗比注:
如果本文看的不錯,想要參與開發(fā),我覺得在這之前需要先讀一下農(nóng)夫的書,請看 《.NET 底層入門》這本書
另外上面說的玩具什么的只是原作者謙虛的說法,其實(shí)這個玩法是可行的,在 Github 有小伙伴在討論,請看?Port JIT and GC to C#?這個鏈接
https://github.com/dotnet/runtime/issues/10158
總結(jié)
以上是生活随笔為你收集整理的Mobius 一个运行在 .NET Core 上的 .NET 运行时的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 五分钟了解dotnetcore配置框架
- 下一篇: Asp.Net Core Filter