5 ms·
OpenJDK used to offer a better baseline performance, particularly at very abstraction-heavy enterprise code. .NET has closed the gap with it since then. Nowaday
by neonsunset 2y ago
OpenJDK used to offer a better baseline performance, particularly at very abstraction-heavy enterprise code. .NET has closed the gap with it since then. Nowadays, .NET can also have quite a Go-like memory profile, especially if you use NativeAOT, but has much higher GC throughput which offers a more foolproof set of tradeoffs. Go has a nice specialized GC design but you cannot tune it at all, and it is centered around moderate allocation rates and consistent latency with small memory footprint. The moment you step outside its boundaries it has problematic regressions .NET's GC implementation is robust against. Java GC implementations are even stronger, but Java also has much higher allocation traffic which offsets some of them.
Where .NET shines is by providing a performance ceiling completely unmatched by neither Java nor Go nor any other GC-based language. Performance ceiling in .NET sits every so slightly below Rust and C, in often an indistinguishable way. It is a very nice experience to write systems code in. It won't give you the same safety for writing concurrent code Rust does, but it is so much more productive than dealing with C or C++, especially when it comes to portable builds and tooling. Of course, it supports only a tiny fraction of platforms compared to C. But your target is more likely to be a server or a consumer device or a comparatively beefy Raspberry PI, and .NET works really well on all of those.
- Capricorn2481 2y ago> Where .NET shines is by providing a performance ceiling completely unmatched by neither Java nor Go nor any other GC-based language How does it do this, exactly? What does .NET have that is better than Java for performant code?
- neonsunset 2y ago> What does .NET have that is better than Java for performant code? CIL bytecode, besides what JVM bytecode exposes, provides much lower level access. As a result, C# and Java are languages of different categories and weight classes completely as of 2025. C# is a proper systems programming language in all the ways Java is not. JVM bytecode is also a more difficult to optimize target because all calls are virtual by default and type information is erased. OpenJDK HotSpot has to perform a lot of work just to get to the baseline where CIL starts at, where you have to explicitly make a call virtual and where type information propagates through generic type arguments. OpenJDK used to have a much more powerful compiler but .NET has closed the gap in almost every area, and in other it has surpassed it, or will surpass in the upcoming release(s). It also has a world of optimizations for structs and struct generics which are monomorphized like in Rust, something OpenJDK might only get to in the future. As I said in my previous comment, performance ceiling of .NET is at approximately the level of C/C++/Rust/Zig. Somewhat lower due to compiler limitations but the gap is small enough for it to be easily competitive. https://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/java.html https://benchmarksgame-team.pages.debian.net/benchmarksgame/... is a good demonstration of performance difference in optimized code in these two languages (note that on <1s execution time benchmarks the startup impact also works against both, so you could look at the comparison between C# AOT and Go to get another picture)
- igouy 2y ago> on <1s execution time benchmarks the startup impact also works against both That would be 5 measurements out of 100? With the tiny tiny benchmarks game programs startup and warmup and shutdown costs must effect measurements longer than 1s -- but less so. https://benchmarksgame-team.pages.debian.net/benchmarksgame/performance/nbodyinprocess.html https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
- neonsunset 2y agohttps://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/csharpcore-csharpaot.html https://benchmarksgame-team.pages.debian.net/benchmarksgame/... Here reverse-complement and spectral-norm have >25% difference. When you look at the main comparison table for either, it might seem that C# lags behind natively compiled languages, but if you look at the NAOT numbers - it is right there next to them. So I'm putting a disclaimer because of it.
- waqar144 2y ago> performance ceiling of .NET is at approximately the level of C/C++/Rust/Zig Not really. You don't have the same level of control over memory in managed languages
- neonsunset 2y agoYou've never actually verified this claim, have you? Next time - please do it. - structs, with auto, sequential and explicit layout, with complex SROA and promotion handling - stack-allocated buffers, unsafe fixed and inline arrays, even managed objects can have their layout configured - monomorphized struct generics compiled the same way they do in Rust - raw and byref pointers with pointer arithmetic - portable and platform-specific SIMD, platform-specific intrinsics - zero-cost interop which enables calls into malloc/free at the cost of C/C++ (you do not actually need this - there is a managed reimplementation of mimalloc which is fully competitive with the original) - static linking with native dependencies when using nativeaot