There's probably something to be said for allowing such a thing in explicitly "unsafe" code, but not in the normal runtime. In fact, it might even be possible now by leveraging some of the existing unsafe bits in .net.
- Extra space for every object to have a refcount
- Extra refcount bookkeeping every time you (re)assign a reference (possibly triggering cache thrashing/false sharing in some multithreaded scenarios), xchgs instead of movs, etc.
- Pointless if you're using bump allocators (they can't reuse the 'freed' memory until the next GC cycle compacts memory anyways), so you're forced to use more complicated allocator designs if you're to reuse said memory.
Cycles mean it still doesn't give you 100% deterministic object destruction either, so you want extra mechanisms for disposing unmanaged resources at controlled times ala IDisposable anyways.
https://www.microsoft.com/en-us/research/wp-content/uploads/...
When you're done with an object (it will almost certainly be an array), push it onto a stack; when you want to allocate, try and pop it off first before allocating fresh. Use stack per thread or locking as appropriate; use multiple stacks with bucketing by size if there's a lot of variance. Use suballocation to reduce reallocating - e.g. allocate 1MB, 2MB, 4MB and so on arrays and keep track of length separately via a slice (array segment).
(ArrayPool in .net encapsulates most of this for you these days, but it's a thing I implemented myself back in .net 2 days.)
That's a GC bug surely?
I had instances where I knew only one of these large structures could fit in memory and had to call gc.collect before allocating a new one, as I would get an outofmemory exception before the garbage collector would kick in by itself.
You can do that with unmanaged objects but it doesn't look like you can with managed objects (other than gc.collect which I saw on other videos is not recommended by microsoft).