What do you mean ?
If you refer to heap allocations, then you can use Box, Arc, Rc. They are not a "garbage collector" nor do they incur performance hits other than a regular heap allocation.
What do you mean ?
If you refer to heap allocations, then you can use Box, Arc, Rc. They are not a "garbage collector" nor do they incur performance hits other than a regular heap allocation.
If your issue is "atomics are slowing down my app", then I assume you already milked the code to the latest micro second of performances everywhere else. This is likely not the case here and not a general advice I would give to anyone.
Remember, some dev in python where concurrency is inexistent, start-up time is horrendous and performances are abysmal compared to rust. (this is exaggerated: of course you can run stuff in parallel in python)
Once you have an Arc<T> you can `as_ref()` to get a &T. So maybe you need an Arc to share something with another thread, so you clone it once. Once you're in that thread though you can go back to just using `&` and never touch the atomic again.
The cost is also more predictable/amortised than classic garbage collection.
The point about predictability is totally valid though (and combined with simplicity is the reason many languages still pick ref counting).
Furthermore Rust can also safely borrow from a refcounted pointer without the need for refcount traffic, which can be quite the performance gain for atomic refcounts (it's nigh irrelevant for non-thread-safe refcounts as those just do a local increment/decrement).
And for systems programming, the often overlooked truth is that people care far less about perfect performance than they do about control - ref counting doesn't give up control to a mysterious oracle running in the background which may or may not wreck your performance in hard to predict ways, it just pays a known cost at the time you use it based on how you're using it. (that's not to say performance is irrelevant, but it's not always the top concern, and with control you can always rewrite slow code as needed).
The obvious question is "why can't we have an optional modern garbage collector built into a systems language?", and it's a good question (I remember reading there was one in rust for a while during early development, but it got removed), I think the main reason is that high quality garbage collectors are incredibly complicated, with many trade offs, and a gc that combines well with the rest of a language and various alternative memory tracking solutions is harder than most. The projects that really want one can always implement their own and choose their own tradeoffs, so there's not many use-cases where a generic language-provided one would justify the complexity of implementing it within the language.
It's possible in C#. Some language and runtime features like lambdas insist on using the GC, but with some care they can be avoided. The usability becomes worse without these features, but IMO that's not a dramatic downgrade.
Many pieces of the standard library in modern .NET don't require managed heap. Instead, they operate on stuff like Span<byte> which can be backed by anything: unmanaged heap, native stack, or even the memory mapped to user space by a Linux device driver (I did it with DRM, V4L2 and ALSA devices).