I noticed memory leaks in my program and tracked it down to the signal handling. Seems crazy that there isn't a leak-free way to do this. I'm not worried about the "still reachable" bytes reported by Valgrind - I'm worried about the "possibly lost" bytes.
minimal reproducible example:
use tokio::signal;
use tokio::time::{sleep, Duration};
async fn sleep1() {
loop {
sleep(Duration::from_secs(1)).await;
println!("sleep1");
}
}
async fn sleep2() {
loop {
sleep(Duration::from_secs(2)).await;
println!("sleep2");
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let s1 = Box::pin(sleep1());
let s2 = Box::pin(sleep2());
let sig = Box::pin(signal::ctrl_c());
tokio::select! {
_ = s1 => {},
_ = s2 => {},
_ = sig => {},
};
println!("shutting down");
Ok(())
}
excerpt from Cargo.toml file:
edition = "2021"
tokio = { version = "1", features = ["full"] }
valgrind output:
==1366460== Command: target/debug/simulation
==1366460==
sleep1
sleep2
sleep1
sleep1
^Cshutting down
==1366460==
==1366460== HEAP SUMMARY:
==1366460== in use at exit: 25,884 bytes in 82 blocks
==1366460== total heap usage: 617 allocs, 535 frees, 145,635 bytes allocated
==1366460==
==1366460== LEAK SUMMARY:
==1366460== definitely lost: 0 bytes in 0 blocks
==1366460== indirectly lost: 0 bytes in 0 blocks
==1366460== possibly lost: 1,188 bytes in 3 blocks
==1366460== still reachable: 24,696 bytes in 79 blocks
==1366460== suppressed: 0 bytes in 0 blocks
==1366460== Rerun with --leak-check=full to see details of leaked memory
==1366460==
==1366460== For lists of detected and suppressed errors, rerun with: -s
==1366460== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)