I've seen comments on a similar memory-leak post but I believe my case is much simpler. I have a loop in which I'm tokio::task::spawn()
-ing lots of tasks, waiting for them and (hopefully) cleaning everything up.
I'd expect memory peak to stabilise but it looks like there is a small increase in each iteration. My test program:
async fn main() {
for i in 0..1000 {
many_tasks().await;
println!("Run {:3}: {:?}", i, procinfo::pid::statm_self());
}
}
async fn many_tasks() {
let handles = (0..5_000_000)
.map(|_| tokio::task::spawn(my_task()))
.collect::<Vec<_>>();
// order doesn't matter, wait for everything
for handle in handles {
handle.await.unwrap();
}
}
async fn my_task() {
tokio::time::delay_for(std::time::Duration::from_secs(5)).await;
}
using
tokio = { version = "0.2", features = ["full"] }
procinfo = "0.4"
My output is:
Run 0: Ok(Statm { size: 771979, resident: 566614, share: 268, text: 131, data: 770801 })
Run 1: Ok(Statm { size: 961931, resident: 756610, share: 273, text: 131, data: 960753 })
Run 2: Ok(Statm { size: 978315, resident: 772994, share: 273, text: 131, data: 977137 })
Run 3: Ok(Statm { size: 994699, resident: 789378, share: 273, text: 131, data: 993521 })
Run 4: Ok(Statm { size: 1011083, resident: 805762, share: 273, text: 131, data: 1009905 })
...
Run 18: Ok(Statm { size: 1011083, resident: 805762, share: 273, text: 131, data: 1009905 })
Run 19: Ok(Statm { size: 1027467, resident: 822146, share: 273, text: 131, data: 1026289 })
Run 20: Ok(Statm { size: 1027467, resident: 822146, share: 273, text: 131, data: 1026289 })
Run 21: Ok(Statm { size: 1043851, resident: 838530, share: 273, text: 131, data: 1042673 })
...
Run 42: Ok(Statm { size: 1076619, resident: 871297, share: 275, text: 131, data: 1075441 })
...
Run 46: Ok(Statm { size: 1093003, resident: 887681, share: 275, text: 131, data: 1091825 })
...
Run 61: Ok(Statm { size: 1125771, resident: 920449, share: 275, text: 131, data: 1124593 })
...
Run 65: Ok(Statm { size: 1142155, resident: 936833, share: 275, text: 131, data: 1140977 })
...
Run 77: Ok(Statm { size: 1158539, resident: 953217, share: 275, text: 131, data: 1157361 })
Run 78: Ok(Statm { size: 1174923, resident: 969601, share: 275, text: 131, data: 1173745 })
...
Run 81: Ok(Statm { size: 1174923, resident: 969601, share: 275, text: 131, data: 1173745 })
^C
on Ubuntu 18.04.4 LTS
(in WLS1) but I've seen similar behaviour in Gentoo.
The interesting bit is that if I change the delay_for()
to 2 seconds, the creep is less pronounced.
Does anyone know what is going on? How can I deal with this -- can I perform some manual cleanup or is it necessary to restart the runtime every now and then?