Personally, I used OCaml while at university to write a programming language (http://jsjs-lang.org) and totally loved it. Real world OCaml is a great resource and I'd definitely recommend giving OCaml a try. My only regret is that I don't get to write OCaml as much as I want to due to the kind of projects I work on, but given that Bucklescript[0] and Reason[1] are moving ahead in full steam, that might change shortly too :)
It's definitely worth playing around with a language from that family. OCaml is maybe slightly more practical than Haskell and it has some nice resources available - in particular Real World OCaml looks really good: https://realworldocaml.org/
If you already know Rust I wouldn't bother learning both - they're very similar languages.
1. Go unsafe on lowest-level operations that simply can't be GC'd. Quite a few of these can be expressed as finite, state machines which can be model-checked for correctness. Static analyzers are also really good these days in whatever code you can avoid dynamic allocation in. The rest of the code is GC'd. That's what the Oberon operating systems do.
2. Use a real-time, low-latency, concurrent GC that basically knocks low single or two digit performance out of the system. Lots of products in embedded Java have special GC's for that. Buy a faster CPU. Trade dollars or performance for productivity and safety.
3. Use a mix of GC's in the system where each one is tuned for the job at hand. You might use a real-time, concurrent one in the kernel. Maybe just reference counting in one more about performance. Maybe a straight-forward one for stuff that's not performance-critical. Could even use one that's mathematically verified for correctness in that situation. JX Operating System is an example of OS that mixes up GC strategies.
That's for software. Your options open up a bit if you can also deploy custom hardware. At the least, a modified soft-core on an FPGA. The LISP machines & maybe a Java CPU of the past often included hardware acceleration for garbage collection. One built the GC right into memory subsystem/interface of the processor where neither the processor nor applications had to be aware of its existence. It just did its thing in parallel to execution of the app. A concurrent, low-latency one integrated with virtual, memory hardware shouldn't take much hardware resources to pull off.
Anyway the syntax is so similar you can learn one and switch to the other with very little pain.