CLR 相比 JVM有哪些先進之處?


雖然只寫了一半但還是先發出來免得坑掉。後面邊討論邊更新吧…

這個問題原文是:

CLR 相比 JVM有哪些先進之處?

留下備份。

首先這個問題按其原樣無法回答,因為CLR與JVM不是可比較的對象。

CLR(Common Language Runtime)是CLI(Common Language Infrastructure)規範中的VES(Virtual Execution System)的一種具體實現,而「JVM」不指定實現的話只能說是一種抽象的規範。

適合比較的對象是:

  • 規範層面:CLI vs JVM
  • 實現層面:CLR / Mono 等 vs HotSpot VM / J9 VM / JRockit VM 等

從規範層面看的話,CLI規範ECMA-335當前最新的版本是2012年出的第6版。我沒太跟進新的CLI規範所以不確定這個版本的CLI與哪個版本的.NET Framework里的CLR對應。

JVM規範The Java? Virtual Machine Specification當前最新的版本則是2015年出的Java SE 8版。

在規範層面上,當前的CLI完勝當前的JVM。

《Virtual Machines: Versatile Platforms for Systems and Processes》一書中有一章專門對比介紹了CLI與JVM的設計,值得一讀。

JVM規範由Sun最初的JVM實現(後來稱為Classic VM)抽象而來,然後幾乎沒有大的改動。後來的更新主要添加了Class文件對泛型信息的有限記錄、註解(annotation)支持、位元組碼校驗器的更新(split verifier / type checking verifier)、invokedynamic及MethodHandle支持、default method支持等。

最初的JVM規範雖然也提到它「可以支持多種語言」,但主要目的還是支持Java一種語言的執行,直到Java 7添加了JSR 292(invokedynamic與MethodHandle)後才有了專門為Java以外的語言設計的功能。

CLI由.NET最初的CLR實現抽象而來,然後與CLR一起逐漸進化。它出現的時間畢竟比JVM規範晚許多,而且一開始就以支持多種語言、多種范型的執行與互操作為設計目的,自然設計得更完善。對歷史有興趣的同學可以搜搜「Project 7」看。

Interviewer: I"ve heard that there was a project where Microsoft started to inte...

Don Syme: That"s a small part of the sequence. The visional design of the .NET platform was very much expected to be a multi-language platform from the start. Right back in 1998, just in fact as our research group in programming languages started at Microsoft and I joined the team and then other 10 of us joined the team, we were approached by a guy called James Plamondon, who started the project called Project 7, which was about getting 7 academic and 7 industrial programming languages on each side to target the .NET common language runtime and really check out if it was good enough, to see if design changes could be made early on in the design process of .NET to make sure it was good enough for a range of programming languages.

Project 7的參與方嘗試了將許多種語言移植到CLR上,包括C、Pascal、Cobol (Fujitsu)、Fortran (Salford)、Haskell、Standard ML、Eiffel、Active Oberon for .NET (ETH)、Gardens Point Component Pascal (QUT)等等。

後來還有更進一步的「Project 7+」。

Technical Overview of the Common Language Runtime

要追尋CLR更早的黑歷史就不得不提微軟的Visual J++。請跳傳送門:微軟當年的 J++ 究竟是什麼?為什麼 Sun 要告它? - RednaxelaFX 的回答

下面先列舉一些點提醒我回頭更新…

Assembly vs Class文件

  • 常量池以stream的方式存在
  • 可以有strong name

CIL(Common Intermediate Language) / MSIL vs Java位元組碼

  • CIL不僅有二進位形式的規範,而且還有標準的文本形式語法;Java位元組碼只有二進位形式的規範
  • 局部變數區里無論什麼類型的值都使用1個slot,而JVM則是long和double用相鄰的2個slot

  • 異常處理支持filter

  • 支持具現化泛型(reified generics)

    • OpenJDK: Valhalla

  • 泛型支持聲明點協變/逆變(declaration-site variance)
    • Java語言層面的泛型則是支持使用點協變/逆變(use-site variance)
  • 支持無符號整數類型(unsigned)

  • 支持用戶自定義值類型(value type)

    • OpenJDK: Valhalla

  • 支持對用戶自定義值類型指定顯式內存布局,可以模擬C的struct和union以便互操作(StructLayout)

    • OpenJDK: Panama

  • 支持檢查溢出的算術運算(checked arithmetic)

  • 支持有保證的尾調用(tail call)

  • 支持unsafe verifiable代碼

  • 支持輕量代碼生成(LCG,Lightweight Code Generation)

  • 支持委託類型(Delegate / MulticastDelegate)

    • CLI Delegate的single cast版本與Java 7的MethodHandle有相似之處
  • 支持方便的P/Invoke和Reverse P/Invoke

    • OpenJDK: Panama

  • 不支持自定義類載入器(custom class loader)。JVM上過於靈活的ClassLoader簡直是頭疼的要命,不支持這個簡直好。

CLI里藏的私貨:Assembly採用PE(Portable Executable)格式。PE是Windows上原生的可執行文件格式。

CLR與Windows的整合

  • Windows Loader可以直接識別.NET Assembly並啟動CLR來執行程序。

  • Windows對GAC(Global Assembly Cache)有文件系統層面的特殊處理,「Fusion」。

  • 與COM有良好的互操作能力。畢竟CLR原本就是希望設計成下一代COM,原本還用過COR這個名字(COM Object Runtime)。
  • 分塊式GC堆(Chunked GC Heap),可以自動擴張和收縮GC堆的大小,並且在Windows這種地址空間比較破碎的環境中可以有效的利用地址空間里的空隙。對應的,JRockit在Windows上則是用filler object來利用空隙。
  • GC堆分為多個空間,特別是高頻堆/低頻堆(high-frequency heap / low-frequency heap)的劃分很有趣。
  • GC支持固定住對象(Object Pinning)
  • GC提供API讓應用程序可以指定native對象的內存壓力,以便GC與native協調工作(System.GC.AddMemoryPressure Method (Int64))
  • 支持Windows的結構化異常處理(SEH)。

CLR 與 一些JVM實現之間有對應物的

  • CLR:DAC / SOS擴展;HotSpot VM:Serviceability Agent;J9 VM:DTFJ / jdmpview
  • CLR:CAS(Code Access Security)與 JVM的沙箱


大部分就是就是 @RednaxelaFX 所說的。 我不懂jvm,所以不多說。只說一個.Net Native。雖然jvm有自己的預編譯技術。但總感覺類似於CLR裡面的ngen,只是把用戶代碼進行簡單的預編譯,而運行的時候還是用的普通的runtime。而.Net Native厲害在於可以通過編譯的tool chain,對所有自己的代碼引用的進行全局分析,打通assembly之前的壁壘,同時對runtime進行優化只保留必要的功能,最後把runtime做到幾百K。性能得到了極大提升。

經過 @RednaxelaFX 的指正,java其實也有類似的是Excelsior JET。但由於不是Oracle,所以感覺一旦java標準變了,他們就會跟不上。但這種對於CLR來講不是問題,下一步我們還有CoreRT,以後你可以自己設置你預編譯的編譯器,以後你可以讓CoreRT鏈接到LLVM可以鏈接到Reyujit等等。而且Excelsior JET居然還收費!!!CoreRT都開源了。。。


F# 有尾調用優化

Clojure / Scala / 其他 JVM 上的函數式語言都沒有

感謝@馬天翼 的提醒,Scala 倒是有一個在編譯器實現的版本(而且效果並不理想

順便那些個連 tail call 和 tail recursion 都分不清的人就別來現眼了


對Windows支持得好


瀉藥。。。對CLR完全不懂啊。。。不過可以看到CLR補丁確實很多的樣子。。。(⊙o⊙)…而且打日本遊戲,修改器,比如某工少女3,你絕對 用不上JVM,那是CLR的天下。。。回答完畢。


不需要手動指定一大堆內存參數,拿來就能跑


JVM 有類型擦除,所以 new T() 這種代碼不能在 JVM 上跑。


首先,CLR和JAVA虛擬機(Java Virtual
Machine,簡稱:JVM)並非一個層面的系統。前者可鬆散地被描述為just-in-time(JIT)優化編譯器和垃圾收集器的混合物,而後者僅僅是一個解釋器;

其次,早先的JVM使用的是第一代解釋器原理,先將java源代碼編譯成位元組碼(bytecode),然後通過JVM對bytecode進行實時解釋。它是在程序使用的時間解釋執行,每次執行都需要重新解釋並執行。而CLR是先通過內置的相應語言的編譯器將源代碼編譯為CIL中間代碼,然後在程序第一次執行時通過JIT
Compilation將中間代碼動態編譯為可執行機器碼。只要該程序駐留在內存中,就不再需要CLR解釋,程序的執行效率跟機器碼一樣快。

隨後,廣受詬病舊的JAVA JVM也更新換代,提供了JIT選項,但是某些方面較為保守。


推薦閱讀:

.NET CLR怎麼保證執行正確的unsafe代碼不掛掉?
C#里的顯式介面實現是什麼原理?
如何開始學習CoreCLR源代碼?
Stack-based 的虛擬機有什麼常用的優化策略?
RyuJIT為什麼比JIT64編譯速度快?

TAG:Java虛擬機JVM | CLR |