Checking for available system memory at runtime

What I want to do at runtime is check if there is available system memory to run a program.
This is running on a Linux system.
Are there native Rust resources to do this, or do I need to use native OS commands?
The simplest possible way is desired.

fn my_cool_program {
   needed_memory = compute_needed_memory
   return "insufficient memory" if insufficient_memory?
   # Do stuff with memory
}

fun insufficient_memory? (needed_memory) -> Bool {
  available_memory = // determine available system memory
  available_memory < needed_memory
}

There are some types with fallible pre-allocation methods. However, be aware that linux by default performs overcommit, where it will gladly "allocate" processes more memory than is collectively available (in the hope/expectation that they won't actually use it all), and then OOM kill processes if things get to the point where the system is actually out of memory.

If we're talking about checking how much memory the system says is currently available to you, it's also a somewhat tricky question because you have RAM, swap, ulimits, possible cgroup or other container-y limits... And even after taking all that into consideration, some other memory hog could come along after your check and you could lose the OOM lottery.

So depending on exactly what you're looking for, it may not be possible without considering the larger environment.

4 Likes

I can run OS commands such as:

$ free 

$ cat /proc/meminfo

but then have to parse out the available memory info.
I just want to know if Rust provides a native way to determine this, and how to use it.
Please don't over complicate this simple task.

There's some crates. I haven't vetted them. Otherwise parsing meminfo is probably how I'd go if I wanted to avoid deps.

In my book it's rude to not point out such major caveats. Maybe you're aware of them; great. That wasn't self-evident in your question.

3 Likes

After a little trial and error, here's how to do it in Crystal.
It returns the number of KB of available system memory (which can be converted to whatever).
This will work for [Li|U]nix systems.

def available_KB
  `cat /proc/meminfo | grep "MemAvailable"`.split(' ')[3].to_i
end

How would you do this in Rust?

let contents=std::fs::read_to_string("/proc/meminfo").expect("Could not read /proc/meminfo");
let mem_info = contents.lines().find(|line| line.starts_with("MemAvailable")).expect("Could not find MemAvailable line");
let size = mem_info.split(" ").nth(3).expect("Found the size");

You could use std::process to call out to cat[1] and grep as you did, but if you're just reading a file you might as well do it natively.

I won't argue that this is a very robust solution, so I'd be wary of using it in any scenario in which I really have to be certain that I have enough memory. But this does exactly what you wrote.


  1. BTW, UUOC: you can just use grep MemAvailable /proc/meminfo in your Crystal code ↩ī¸Ž

You said "Linux" in your question, but didn't give a version. According to my manpage, /proc/meminfo is only available from Linux 3.14 onwards. And this question has inherent complexity, we didn't make that up to annoy you.

1 Like

Thank you very much.
There's nothing that's life and death for this particular usage.
Before, I just ran the program, and if there wasn't enough memory it just bombed.
Now the part that does calculations won't even get used unless there's enough memory for it.

FYI. Here's the working function.
If this can be made simpler|better let me know.

fn available_memory() -> usize {
  let contents=std::fs::read_to_string("/proc/meminfo").expect("Could not read /proc/meminfo");
  let mem_info = contents.lines().find(|line| line.starts_with("MemAvailable")).expect("Could not find MemAvailable line");
  let size = mem_info.split(" ").nth(3).expect("Found the size");
  let available_mem: usize = size.parse().unwrap();
  available_mem
}

In case people need|want these system memory values too.

fn available_system_memory() -> usize {
  let contents=std::fs::read_to_string("/proc/meminfo").expect("Could not read /proc/meminfo");
  let mem_info = contents.lines().find(|line| line.starts_with("MemAvailable")).expect("Could not find MemAvailable line");
  let size = mem_info.split(" ").nth(3).expect("Found the size");
  let available_mem: usize = size.parse().unwrap();
  available_mem  // in kilobytes KB
}

fn total_system_memory() -> usize {
  let contents=std::fs::read_to_string("/proc/meminfo").expect("Could not read /proc/meminfo");
  let mem_info = contents.lines().find(|line| line.starts_with("MemTotal")).expect("Could not find MemAvailable line");
  let size = mem_info.split(" ").nth(7).expect("Found the size");
  let total_mem: usize = size.parse().unwrap();
  total_mem      // in kilobytes KB
}

fn free_system_memory() -> usize {
  let contents=std::fs::read_to_string("/proc/meminfo").expect("Could not read /proc/meminfo");
  let mem_info = contents.lines().find(|line| line.starts_with("MemFree")).expect("Could not find MemAvailable line");
  let size = mem_info.split(" ").nth(8).expect("Found the size");
  let free_mem: usize = size.parse().unwrap();
  free_mem      // in kilobytes KB
}

1 Like