29 comments

[ 4.3 ms ] story [ 74.7 ms ] thread
Interesting, I mostly work in JVM, and am always impressed how much more advanced feature-wise the .NET runtime is.

Won't this potentially cause stack overflows in programs that ran fine in older versions though?

Very mixed feelings about this as there’s a strong case for the decisions made here but it also moves .NET further away from WASMGC, which makes using it in the client a complete non-starter for whole categories of web apps.

It’s a missed opportunity and I can’t help but feel that if the .NET team had gotten more involved in the proposals early on then C# in the browser could have been much more viable.

A lot of the features here, stuff like escape analysis for methods etc. does not directly involve the GC - it reduces the amount of objects that go to the GC heap so the GC has less work to do in the first place.
How would this move .NET further away from WASMGC? This is a new GC for .NET, but doesn't add new things to the language that would make it harder to use WASMGC (nor easier).

For example, .NET has internal pointers which WASMGC's MVP can't handle. This doesn't change that so it's still a barrier to using WASMGC. At the same time, it isn't adding new language requirements that WASMGC doesn't handle - the changes are to the default GC system in .NET.

I agree it's disappointing that the .NET team wasn't able to get WASMGC's MVP to support what .NET needs. However, this change doesn't move .NET further away from WASMGC.

Are you now allowed to benchmark the .Net runtime / GC?

Edit: Looks like you are allowed to benchmark the runtime now. I was able to locate an ancient EULA which forbade this (see section 3.4): https://download.microsoft.com/documents/useterms/visual%20s...

> You may not disclose the results of any benchmark test of the .NET Framework component of the Software to any third party without Microsoft’s prior written approval.

Use managed language, it will handle memory stuff for you, you don’t have to care.

But also read these 400 articles to understand our GC. If you are lucky, we will let you change 3 settings.

In my 20+ years using C#, there's only been one instance where I needed to explicitly control some behavior of the GC (it would prematurely collect the managed handle on a ZMQ client) and that only required one line of code to pin the handle.

It pretty much never gets in your way for probably 98% of developers.

DATAS has been great for us. Literally no effort, upgrade the app to net8 and flip it on. Huge reduction in memory.

TieredCompilation on the other hand caused a bunch of esoteric errors.

FWIW Tiered Compilation has been enabled on by default since .NET Core 3.1. If the code tries to use refection to mutate static readonly fields and fails, it's the fault of that code.
A hobby audio and text analysis application I've written, with no specific concern for low level performance other than algorithmically, runs 4x as fast in .net10 vs .net8. Pretty much every optimization discussed here applies to that app. Great work, kudos to the dotnet team. C# is, imo, the best cross platform GC language. I really can't think of anything that comes close in terms of performance, features, ecosystem, developer experience.
> I really can't think of anything that comes close in terms of [...] developer experience.

Of all the languages that I have to touch professionally, C# feels by far the most opaque and unusable.

Documentation tends to be somewhere between nonexistant and useless, and MSDN's navigation feels like it was designed by a sadist. (My gold standard would be Rustdoc or Scala 2.13 era Scaladoc, but even Javadoc has been.. fine for basically forever.) For third-party libraries it tends to be even more dire and inconsistent.

The Roslyn language server crashes all the time, and when it does work.. it doesn't do anything useful? Like cross-project "go-to-definition" takes me to either a list of members or a decompiled listing of source code, even when I have the actual source code right there! (I know there's this thing called "SourceLink" which is.. supposed to solve this? I think? But I've never seen it actually use it in practice.)

Even finding where something comes from is ~impossible without the language server, because `using` statements don't mention.. what they're even importing. (Assuming that you have them at all. Because this is also the company that thought project-scoped imports were a good idea!)

And then there's the dependency injection, where I guess someone thought it would be cute if every library just had an opaque extension method on the god object, that didn't tell you anything about what it actually did. So good luck finding where the actual implementation of anything is.

Except for F#, which also gets all the .NET10 cross-platform GC improvements for free and is a better programming language than C#.
C# will be a force to reckon with if/when discriminated unions finally land as a language feature.
Or you can use the "C# without the line noise", which goes under the name of F#.
> I really can't think of anything that comes close in terms of performance, features, ecosystem, developer experience.

This is also why I prefer to use Unity over all other engines by an incredible margin. The productivity gains of using a mature C# scripting ecosystem in a tight editor loop are shocking compared to the competition. Other engines do offer C# support, but if I had to make something profitable to save my own standard of living the choice is obvious.

There's only two vendors that offer built-in SIMD accelerated linear math libraries capable of generating projection matrices out of the box. One is Microsoft and the other is Apple. The benefits of having stuff like this baked into your ecosystem are very hard to overstate. The amount of time you could waste looking for and troubleshooting primitives like this can easily kill an otherwise perfect vision.

Java?

Is supported on more platforms, has more developers, more jobs, more OSS projects, is more widely used (Tiobe 2024). Performance was historically better, but c# caught up.

>runs 4x as fast in .net10 vs .net8.

Is this open source? Do you have numbers? I've been coding in .NET since it was "a thing" and frankly I'm having trouble mapping the optimizations to a local application at that magnitude.

The optimizations are seen at scale, they really won't mean much for your local application. Not a 3x+ improvement at least.

I am considering dotnet Maui for a project. On the one hand, I am worried about committing to the Microsoft ecosystem where projects like Maui have been killed in the past and Microsoft has a lot of control. Also XML… On the other hand, I’ve been seeing so many impressive technical things about dotnet itself. Has anyone here used Maui and wants to comment on their experience?
Last time I had to create a C# desktop app, I went with Blazor Hybrid [1]. I'd say it's "Electron for C#". I don't want to use outdated stuff like WPF / WinForms, and I don't trust more recent frameworks, so for me building on top of the web platform felt safest.

[1]: https://learn.microsoft.com/en-us/aspnet/core/blazor/hybrid/...

I wonder if this makes .net competitive for high frequency trading...
I always found that Jit and GC are a marriage destined to come together, but never found one another entirely. Jit marks the hotloop in code- and thus can tell the GC in detail what a generation really is and how long a generation lifetime really lasts.

It can reveal secret cull conditions for long generational objects. If that side-branch is hit in the hot-loop, all longterm objects of that generation, are going to get culled, in a single stroke… so bundle them and keep them bundled. And now they started using it, to at least detect objects that do not escape lambdas. So its all stack, no more GC involved at all. Its almost at the static allocation thing we do for games. If the model proofs that every hotloop 5 objects are allocated and life until a external event occurs- static allocation and its done.

Great start. But you could do so much more than that with this. If you write a custom JIT whose goal is not just to detect and bytecompile hotloops, but to build a complete multi-lifetime model of object generation.

(comment deleted)
Do these updates mean that the JIT can finally optimize LINQ away into simple loops?
Garbage collection improvements are always welcome. We've had some .NET services where GC pauses were causing noticeable latency spikes under load.

I think the regional GC approach is potentially promising if it’s for applications with large heaps. I’ll bet most web apps probably won't notice much difference though.