Memory Usage Analysis
Recipe | Crates | Categories |
---|---|---|
Profile Heap Memory with dhat | ||
Examine Memory with Debugging Tools | ||
Leak Detection | ||
Execution Time Measurement | ||
Use Tracing to Understand Allocation Patterns |
Profile Memory and Track Allocations
- While not Rust-specific,
valgrind
⮳ (withmassif
ormemcheck
) is a very common and powerful memory profiler. You'd run your Rust program under Valgrind. heaptrack
⮳ is a heap profiler that can track memory allocations.
Profile Heap Memory with dhat
dhat
⮳ is a library for heap profiling and ad-hoc profiling with DHAT.
// `dhat` provides heap profiling and ad-hoc profiling capabilities to Rust, // similar to those provided by `DHAT`, a powerful heap profiler that // comes with `Valgrind`. Warning: This crate is experimental. // First, add to your `Cargo.toml`: // [dependencies] // dhat = "0.3.3" // // # You should only use `dhat` in release builds. // [profile.release] // debug = 1 // // # Create features that lets you easily switch profiling on and off: // [features] // dhat-heap = [] # if you are doing heap profiling // dhat-ad-hoc = [] # if you are doing ad hoc profiling // The heap profiling works by using a global allocator that wraps the system // allocator and tracks all heap allocations. // We set `dhat::Alloc` as the global allocator // using the #[global_allocator] attribute. #[global_allocator] static ALLOC: dhat::Alloc = dhat::Alloc; // When you run the code below with: // cargo run --features dhat-heap // `dhat` will collect heap profiling information. // The profiling data will be saved in a file named `dhat-heap.json` // in the current directory. You can then use e.g. // https://nnethercote.github.io/dh_view/dh_view.html // to analyze the profiling data. // The profiler also prints to `stderr`, like: // dhat: Total: 9,200 bytes in 10 blocks (note: "block" = allocation) // dhat: At t-gmax: 5,120 bytes in 2 blocks // dhat: At t-end: 1,024 bytes in 1 blocks fn heap_profiling() { // Start the heap profiling session #[cfg(feature = "dhat-heap")] let _profiler = dhat::Profiler::new_heap(); // Example code to profile: // Create a vector and pushes 1000 elements into it. let mut vec = Vec::new(); for i in 0..1000 { vec.push(i); } #[cfg(feature = "dhat-heap")] println!("Memory profiling complete!"); } // Ad hoc profiling involves manually annotating hot code points. // Run with: cargo run --features dhat-ad-hoc // The profiler prints to `stderr`: // dhat: Total: 100,000 units in 100,000 events // dhat: The data has been saved to dhat-ad-hoc.json, and is viewable with // dhat/dh_view.html fn adhoc_profiling() { #[cfg(feature = "dhat-ad-hoc")] let _profiler = dhat::Profiler::new_ad_hoc(); fn hot_function() { #[cfg(feature = "dhat-ad-hoc")] dhat::ad_hoc_event(1); } for _ in 0..100000 { hot_function(); } } pub fn main() { heap_profiling(); adhoc_profiling(); } // `dhat` also supports heap usage testing, where you can write tests and then // check that they allocated as much heap memory as you expected. #[test] fn heap_usage_testing() { // `testing()` allows the use of dhat::assert! and related macros, // and disables saving of profile data on Profiler drop. let _profiler = dhat::Profiler::builder().testing().build(); let _v1: Vec<i32> = vec![1, 2, 3, 4]; let v2: Vec<u8> = vec![5, 6, 7, 8]; drop(v2); let stats = dhat::HeapStats::get(); // Total allocations and number of bytes: // dhat::assert_eq!(stats.total_blocks, 2); dhat::assert_eq!(stats.total_bytes, 20); // Allocations and number of bytes at the point of peak heap size: // dhat::assert_eq!(stats.max_blocks, 2); dhat::assert_eq!(stats.max_bytes, 20); // Now a single allocation remains alive. // dhat::assert_eq!(stats.curr_blocks, 1); dhat::assert_eq!(stats.curr_bytes, 16); } // Example adapted from https://docs.rs/dhat/latest/dhat/
Leak Detection
valgrind
⮳ (withmemcheck
) is excellent for detecting memory leaks.- Address Sanitizer (
ASan
) can detect memory leaks and other memory errors. Enable it with compiler flags (e.g.,-fsanitize=address
).
Examine Memory with Debugging Tools
gdb
⮳, lldb
⮳ debuggers can be used to inspect memory, examine variables, and track allocations.
Use Tracing to Understand Allocation Patterns
tracing
⮳ can help you understand the flow of your program and identify areas where excessive allocations might be occurring.
See Tracing.
Execution Time Measurement
measure_time
⮳ can help you measure the execution time of code blocks, which can be useful when investigating memory-related performance issues.