https://learn.microsoft.com/en-us/dotnet/api/system.runtime....
There is always C++ for those that don't want a tracing GC.
I want to be able allocate/deallocate C# objects.
Maybe I am missing something, but this doesn't seem like a very complicated ask. Granted, some developers would absolutely blow their feet off with this, but that's why you don't make it a default thing. Hide it behind a csproj flag and throw a runtime exception if the developer presses the GC.NapTime() red button without configuring the runtime appropriately.
There are a lot of use cases where you can strategically reorganize the problem and sidestep the need to meticulously clean your heaps. Running a supervisory process (which is allowed to GC itself) that periodically resets the principal ZGC process via business events or other heuristics is a pretty obvious path to me. Round-based multiplayer gaming seems well-aligned if you can keep allocations to a dull roar.
There is also API to temporarily suppress GC: https://learn.microsoft.com/en-us/dotnet/api/system.gc.tryst...
My use case is such that I have already done everything in my power to minimize allocations, but I have to use some parts of the framework which generate a small amount of ambient trash as a consequence of their operation. My desire to suppress GC is not so much about my own allocation story as it is keeping the gentle, gradual allocations from auxiliary framework items from triggering a nasty GC pause.
My biggest pain point - every time an HttpContext is used there is some degree of trash that accumulates. I have zero control over this unless I want to write my own HTTP+web socket implementation from zero.
The current solution for me is to GC as often as possible in workstation mode, but I would find a zero GC solution even better for this specific scenario. I suspect "rapid GC" is only sustainable while total working set remains small-ish. In the future, I may want to operate with working sets measured upwards of 10 gigabytes.
I can see something like this be useful in certain circumstances. But I would intuitively assume that gen0 collection is probably a better compromise.
Unless you have a remarkably specific need, disabling GC is almost always the wrong path.
The "correct" way is to manipulate GC. You can suspend, manually start a GC run, pin memory, exempt an object from GC, and a few other things I've never played with.
AFAIK the only thing you can't do is immediately deallocate an object. But honestly I can't come up with a situation where an object must be deallocated immediately. Depending on your exact use case, there's ways around that if you really, really need to.
In general, the GC will almost always perform better than any manual manipulation you'd do to it. The main "acceptable" use is suspending GC inside very hot code and deferring the collection until your program is less busy. Like suspending GC while processing one frame in a game, and manually running GC in the space between frames. Even then, this is still discouraged.
Out of curiosity, what's your use case here? I really can't think of any situation that doesn't have a better solution.
now that you can return refs instead of just passing them around, that's also really nice for cases where you want to pass around an interior pointer into some sort of data structure - you can use refs whether a value is allocated via the GC or malloc or stackalloc.
Is it impossible to prove memory safety in the general case due to the halting problem?
https://www.microsoft.com/en-us/research/publication/perceus...
It's interesting how much there still is to discover in this space, despite decades of research.
/memorymodel:scoped_refcounted
Typically you'd see a model that allows file-by-file transitions so that you can slowly clean up a codebase to make it 'safe' for a given model. This is (afaik) roughly how non-nullable references were added to C#.
If you look at it from that perspective, I don't think you would end up wanting the compiler to help you with this. You'd introduce some sort of 'refcounted pointer' type, maybe called Rc<T>, which wraps a T* + a deallocator. I can't imagine C# ever letting you overload the -> operator though so the ergonomics would be bad.