色婷婷狠狠18禁久久YY,CHINESE性内射高清国产,国产女人18毛片水真多1,国产AV在线观看

Java和C#最大的不同是什么?

吉茹定2年前14瀏覽0評論

我覺得拋開語法而談,最主要的還是對底層的控制能力不同。

C#一開始雖然借鑒Java,但是目的完全不是為了造一個betterJava,而是造一個betterC++。游戲引擎們偏愛C#也是有這一層原因在里面。

比如在C#里面你能干的:

上述代碼會輸出10,為什么?因為.NET中數組的長度存儲于數組第一個元素之前的8字節內存中。如果你再接著輸出*((long*)p-2),將會直接得到這個對象的TypeHandle地址:

然后拿著這個指針又接著能去訪問對象的MethodTable


再有你還可以手動在棧上分配空間:


接著你想繞過GC直接手動分配堆內存:

上述調用等價于你在C語言中調用的malloc,此外還有AllocAlignedReallocAllocZeroed等等,可以直接控制內存對齊。


接下來你想創建一個顯式內存布局的結構Foo

然后你就成功模擬出了一個C的Union,之所以會有上面的輸出,是因為單精度浮點數1的二進制表示為0x00111111100000000000000000000000,以小端方式存儲后占4個字節,分別是0x00000000、0x00000000、0x10000000、0x00111111。


進一步,你還能直接從內存數據沒有任何拷貝開銷地構造對象:

甚至這樣:

從堆內存創建自然也沒問題:


再比如,此時你面前有一個使用C++編寫的庫,其中有這么一段代碼:

然后我們編寫如下C#代碼:

上面的代碼干了什么事情?我們將C#的函數指針傳到了C++代碼中,然后在C++側調用C#函數生成了一個字符串wwwww,然后將這個字符串返回給C#側。而就算不用函數指針換成使用委托也沒有區別,因為.NET中的委托下面就是函數指針。

甚至,如果我們不想讓.NET導入foo.dll,我們想自行決定動態庫的生命周期,還可以這么寫:

上面這些都不是Windows專用,在Linux、macOS上導入.so.dylib都完全不在話下。


再有,我們有一些數據想要進行計算,但是我們想使用SIMD進行處理,那只需要這么寫:

可以看看在X86平臺上生成了什么代碼:

平臺判斷的分支會被JIT自動消除。但其實除了手動編寫SIMD代碼之外,前兩個分支完全可以不寫,而只留下:

因為現階段當循環邊界條件是向量長度時,.NET會自動為我們做向量化并展開循環。


那么繼續,我們還有refinout來做引用傳遞。

假設我們有一個很大的struct,我們為了避免傳遞時發生拷貝,可以直接用in來做只讀引用傳遞:

而對于小的struct,.NET有專門的優化幫我們徹底消除掉內存分配,完全將struct放在寄存器中,例如如下代碼:

上述代碼GetDistance考慮是個熱點路徑,因此我加MethodImplOptions.AggressiveInlining來指導JIT有保證地內聯此函數,最后為Test生成了如下的代碼:

全程沒有一句指令訪存,非常的高效。

我們還可以借用ref的引用語義來做原地更新:

甚至還能搭配指針和手動分配內存來使用:

C#的泛型不像Java采用擦除,而是真真正正會對所有的類型參數特化代碼(盡管對于引用類型會共享實現采用運行時分發),這也就意味著能最大程度確保性能,并且對應的類型擁有根據類型參數大小不同而特化的內存布局。還是上面那個Point的例子,我們將下面的數據int換成泛型參數T,并做值類型數字的泛型約束:

無論是Test1還是Test2,生成的代碼都非常優秀,不僅不存在任何的裝箱拆箱,甚至沒有任何的訪存操作:


接著講,我們有時候為了高性能想要臨時暫停GC的回收,只需要簡單的一句:

就能告訴GC如果還能分配128mb內存那就不要做回收了,然后一段時間內以后的代碼我們盡管在這個預算內分配內存,任何GC都不會發生。甚至還能阻止在內存不夠分配的情況下進行阻塞式FullGC:

代碼執行完了,最后的時候調用一句:

即可恢復GC行為。

除此之外,我們還能在運行時指定GC的模式來最大化性能:


更進一步,我們甚至可以直接將堆內存中的代碼執行,在.NET上自己造一個JIT,直接從內存創建一塊可執行的區域然后往里面塞一段代碼用來將兩個32位整數相加:


除此之外,C#還有更多數不清的底層寫法來和操作系統交互,甚至利用C#的編譯器取消鏈接到自己的標準庫,直接用從0開始造基礎類型然后通過NativeAOT編譯出完全無GC、能夠在裸機硬件上執行引導系統的EFI固件都是沒有問題的,參考https://github.com/MichalStrehovsky/zerosharp


另外還有ILGPU讓你把C#代碼直接跑在GPU上面,以及跑在嵌入式設備上直接操作I2C、PWM、GPIO等等,就不再舉例子了。


而C#已經進了roadmap的后續更新內容:允許聲明引用字段、添加表達固定長度內存的類型、允許傳數組時消除數組分配、允許在棧上分配任何對象等等,無一不是在改進這些底層性能設施。


以上就是我認為的C#和Java最大的不同。

在C#中當你不需要上面這些的東西時,它們仿佛從來都不存在,允許動態類型、不斷吸收各種函數式特性、還有各種語法糖加持,簡潔度和靈活度甚至不輸Python,非常愉快和簡單地就能編寫各種代碼;而一旦你需要,你可以擁有從上層到底層的幾乎完全的控制能力,而這些能力將能讓你有需要時無需思考各種奇怪的workaround就能直接榨干機器,達到C、C++的性能,甚至因為有運行時PGO而超出C、C++的性能。