It's hard to detect memory leak, with a global allocator, we can trace the alloc add dealloc, if we record the call stacks of alloc operation, then we can see where the code lead memory leak. This tool do NOT record ALL allocation, but delete the record when dealloc.
Powerd by global allocator + heapless + backtrace, it's only support nightly toolchain, caused by new_uninit features.
Add this to your cargo.toml:
leak-detect-allocator = {git = "https://github.com/lynnux/leak-detect-allocator.git"}Example:
use leak_detect_allocator::LeakTracerDefault;
#[global_allocator]
static LEAK_TRACER: LeakTracerDefault = LeakTracerDefault::new();
#[tokio::main]
async fn main() -> Result<(), BoxError> {
LEAK_TRACER.init();
tokio::spawn(async move {
loop {
tokio::signal::ctrl_c().await.ok();
let mut out = String::new();
let mut count = 0;
let mut count_size = 0;
LEAK_TRACER.now_leaks(|address: usize, size: usize, stack: &[usize]| {
count += 1;
count_size += size;
out += &format!("leak memory address: {:#x}, size: {}\r\n", address, size);
for f in it {
// Resolve this instruction pointer to a symbol name
out += &format!(
"\t{:#x}, {}\r\n",
*f,
LEAK_TRACER.get_symbol_name(*f).unwrap_or("".to_owned())
);
}
true // continue until end
});
out += &format!("\r\ntotal address:{}, bytes:{}\r\n", count, count_size);
std::fs::write("foo.txt", out.as_str().as_bytes()).ok();
}
});
}When CTRL+C, it will get a "foo.txt", and the output is like:
leak memory address: 0x44e440, size: 10
0x13fe09443, backtrace::backtrace::trace_unsynchronized<closure-0>
0x13fe09443, leak_detect_allocator::{{impl}}::alloc<leak_detect_allocator::LeakData<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B1>, typenum::bit::B0>>,typenu
0x13fe09443, flashcore::_::__rg_alloc
0x13fe09443, alloc::alloc::alloc
0x13fe09443, alloc::alloc::{{impl}}::alloc
0x13fe09443, alloc::raw_vec::RawVec<u8, alloc::alloc::Global>::allocate_in<u8,alloc::alloc::Global>
0x13fe09443, alloc::raw_vec::RawVec<u8, alloc::alloc::Global>::with_capacity<u8>
0x13fe09443, alloc::vec::Vec<u8>::with_capacity<u8>
0x13fe09443, alloc::slice::hack::to_vec<u8>
leak memory address: 0x4508c0, size: 30
0x13fe09443, backtrace::backtrace::trace_unsynchronized<closure-0>
0x13fe09443, leak_detect_allocator::{{impl}}::alloc<leak_detect_allocator::LeakData<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B1>, typenum::bit::B0>>,typenu
0x13fe09443, flashcore::_::__rg_alloc
0x13fe09443, alloc::alloc::alloc
0x13fe09443, alloc::alloc::{{impl}}::alloc
0x13fe09443, alloc::raw_vec::RawVec<u8, alloc::alloc::Global>::allocate_in<u8,alloc::alloc::Global>
0x13fe09443, alloc::raw_vec::RawVec<u8, alloc::alloc::Global>::with_capacity<u8>
0x13fe09443, alloc::vec::Vec<u8>::with_capacity<u8>
0x13fe09443, alloc::slice::hack::to_vec<u8>
...
total address:38, bytes:6373
Stack calls seems better in debug version.
More stack by this:
use leak_detect_allocator::LeakTracer;
#[global_allocator]
static LEAK_TRACER: LeakTracer<20> = LeakTracer::<20>::new();On Win7 64, if you encounter deadlock, you can try place a newer version of dbghelp.dll to your bin directory.
2021/28/6, use cpp(c++11) to speedup for rust debug version.