Handling memory failure

Hi

Is there a way for a rust program to handle memory failure ?

like

let mut my_string = String::try_new()?;
my_string.try_push("test")?;

/// and the same for every other type like vec, map, etc...

Also, I thought about an interface, like thread::scope

fn main(){
   alloc::fallible(|| {
            // my code that can have memory failure
   })
}

Is there a book or a tutorial to make a safe-from-memory-failure rust program ?

Thanks

1 Like

I think you are looking for this

Otherwise,

try_reserve methods - Available on stable Vec, String, VecDeque, HashMap, HashSet:

let mut v = Vec::new();
v.try_reserve(1000)?;  // Returns Result<(), TryReserveError>
v.push(42);            // Won't allocate, capacity already reserved

try_with_capacity:
let v: Vec<i32> = Vec::try_with_capacity(1000)?;
1 Like

Easy. Allocate all the memory you will ever need at program start up. If that fails do not start.
Well, not so easy. But that is what I have seen embedded systems applications do many times where memory is in short supply.

2 Likes

Hm.. that may be the case for embedded stuff, but I have seen that they use a different fallible implementation for some of the collections (Vec I am sure of) in kernel code.

I have no idea really. Except underneath Vec and such there is malloc() from libc. Which pretty much never fails on systems that support virtual memory like Linux and probably Mac and Windows. Instead when you ask for a memory block it just reserves a virtual memory space (just a range of addresses) and returns OK. Even if there is not actually enough RAM for the allocation you want at the time. It's not until you actually read and/or write to somewhere in that address space later that the OS will actually map a memory page for you at that address. Which might then fail and bring down your whole program.

For the reason the advice for embedded Linux dev was not to simply malloc() the memory you want at start up but also to write into it, just a byte in every 4K page would do, to make sure it is really available.

This whole memory business is very complicated...

1 Like

It is very limited. Rust's standard library has a deeply rooted pessimistic assumption that Linux is the only platform that matters, and everyone has overcommit enabled and configured to kill, and that if it's not possible to handle OOM in 100% of cases then it's not worth bothering to handle it in ~90% of cases.

In practice what you can do is try_reserve(). Vec and String guarantee they will use the reserved capacity when it's sufficient. new doesn't allocate.

Use Cap — Rust memory management library // Lib.rs if you need reliable memory limit reported on Linux.

3 Likes

Unfortunately it's not just Linux. While Windows XP or Windows NT 3.51 may handle OOM just fine, modern versions of Windows and macOS are more-or-less hopeless: if you run out of swap space then the whole thing becomes unusable, not just your program.

When essentially all major OSes don't handle OOM situation well trying to handle it in your app is more-or-less pointless… except if you write embedded code or your own kernel.

P.S. Actually I suspect Rust's history plays even bigger role: Rust was initially envisioned as yet-another-modern language with tracing GC and thus OOM-intolerant. At some point tracing GC idea was nuked… but I suspect at this point it was too late to radically change the design of the whole standard library.