Hello!
I am experiencing unexpectedly high memory usage using Rust's MPSC channels.
To reproduce it, I made an example (playground --- sorry, it does not run there due to a stack overflow):
use std::{thread, time};
fn main() {
use std::sync::mpsc::channel;
//use flume::unbounded as channel;
//use crossbeam_channel::unbounded as channel;
let (sender, receiver) = channel();
let consume = thread::spawn(move || {
for x in receiver.into_iter() {
// comment out the next line to consume less memory
thread::sleep(time::Duration::from_millis(10));
//println!("receiving");
}
println!("done processing");
thread::sleep(time::Duration::from_millis(5000));
});
for i in 0..1024 {
let v = [0; 1024 * 1024];
sender.send(Vec::from(v)).unwrap();
}
println!("done sending");
// signalise that we are done sending
drop(sender);
// wait for all sent things to be consumed
consume.join().unwrap();
println!("done receiving");
thread::sleep(time::Duration::from_millis(5000));
}
In this example, we send a number of objects over a channel and process them in a different consume
thread. When the thread consumes each received object "fast enough" (that is, without the thread::sleep()
), then the total memory usage remains low. However, if the thread takes a bit of time to process objects (simulated with thread::sleep()
), then the memory usage attains a certain level from which it decreases only when the consumer thread finishes.
In this graph, the actual memory usage drops when "done receiving" is printed, that is, when the thread exits.
Instead, I would have expected that as the consumer thread receives objects, the memory usage would go down gradually.
This behaviour occurs with several channel implementations, namely crossbeam-channel
, flume
, and std::sync::mpsc
.
(For flume
, the memory usage drops already at "done processing", but still, that's later than expected.)
This is a real problem in my application, because it increases RAM usage from 4GB to nearly 24GB!
Do you have any idea how to make RAM usage decrease when receiving items, that is, to get to the "expected" memory usage in the graph?