Why do you want that? This does not really win performance when you start to care about it yet imposes severe requirements on the programmer to ensure that manually deallocated object is not referenced anywhere.
All I want for Christmas this year is for Java Epsilon GC [0] to be made available in .NET.
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.
Given that GC exists as a standalone .dll / .so when targeting JIT, you could theoretically replace it with your own implementation that only supports allocation. But realistically this may not be desirable since the allocation traffic in applications can be pretty high and require a lot of RAM to not quickly go OOM without reclaiming the memory.
> the allocation traffic in applications can be pretty high
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.
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.
It's been pretty straightforward to do this since the start, since C# has had structs and pointers the whole time. It's gotten a lot easier now that there are safe bounds-checked pointer abstractions (Span and Memory) so that you can work with raw memory anywhere you want without constantly having to manually do safety checks to avoid heap corruption. 'where T : unmanaged' means you can finally write generics around pointers too.
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.
Mojo’s model looks interesting here. No GC and no ref counts, something akin to a reference count mechanism at compile time. Not sure how it works exactly and the documentation (as is the whole project) very alpha.
It is like Xerox and ETHZ use of memory safe systems languages for graphical workstations, monetary and human issues hinder adoption of great research ideas.
The problem with doing memory model stuff as a compile time flag is it's all-or-nothing, it becomes very hard to transition a whole app to it or even dream of making something like the whole standard library support it.
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.