A lightweight Rust library for analyzing memory usage of structs, providing stack size and approximate heap memory reporting through derive macros.
- Stack Size Analysis - Measure the stack footprint of your structs
- Deep Heap Tracking - Approximate heap memory usage including nested allocations
- Memory Tree Visualization - Detailed breakdown of memory usage by field
- Zero Runtime Overhead - All calculations use derive macros
- Generic Support - Works with generic types and complex nested structures
Since this crate is not yet published to crates.io, you can use it directly from GitHub:
Add this to your Cargo.toml:
[dependencies]
struct_mem = { git = "https://github.com/StreamIntelligenceLab/struct-mem" }Clone the repository and reference it locally:
git clone https://github.com/StreamIntelligenceLab/struct-mem.gitThen in your Cargo.toml:
[dependencies]
struct_mem = { path = "../struct-mem/struct_mem" }use struct_mem::{DeepMem, MemTree, StructMem, report_deep, report_stack, report_tree};
#[derive(StructMem, DeepMem, MemTree)]
struct Person {
name: String,
age: u32,
hobbies: Vec<String>,
}
fn main() {
let person = Person {
name: "Alice".to_string(),
age: 30,
hobbies: vec!["reading".to_string(), "coding".to_string()],
};
// Method 1: Using trait methods directly
println!("Stack size: {}", person.stack_size());
println!("Heap bytes: {}", person.heap_bytes());
println!("Total bytes: {}", person.total_bytes());
// Method 2: Using convenience macros
report_stack!(&person);
report_deep!(&person);
// Method 3: Detailed memory tree
report_tree! (&person);
}Measures only the stack footprint of your struct:
#[derive(StructMem)]
struct Config {
enabled: bool,
timeout: u32,
}
let config = Config { enabled: true, timeout: 5000 };
println!("Stack size: {} bytes", config.stack_size());Includes both stack and heap allocations:
#[derive(StructMem, DeepMem)]
struct Data {
buffer: Vec<u8>,
label: String,
}
let data = Data {
buffer: vec![0; 1024],
label: "test".to_string(),
};
println!("Stack: {} bytes", data.stack_size());
println!("Heap: {} bytes", data.heap_bytes());
println!("Total: {} bytes", data.total_bytes());Provides field-by-field memory analysis:
#[derive(StructMem, DeepMem, MemTree)]
struct Team {
name: String,
members: Vec<Person>,
}
let team = Team {
name: "Engineering".to_string(),
members: vec![/* ... */],
};
report_tree!(&team);
// Output shows memory usage for each fieldreport_stack!(&value)- Print stack sizereport_deep!(&value)- Print total memory (stack + heap)report_tree!(&value)- Print detailed memory breakdowntrack_deep!({ expression })- Track memory of an expression and print it
#[derive(StructMem, DeepMem, MemTree)]
struct Team {
name: String,
members: Vec<Person>,
metadata: std::collections::HashMap<String, String>,
}
let team = Team {
name: "Engineering". to_string(),
members: vec![
Person {
name: "Bob".to_string(),
age: 25,
hobbies: vec! ["gaming".to_string()],
},
Person {
name: "Charlie".to_string(),
age: 35,
hobbies: vec!["hiking".to_string(), "photography".to_string()],
},
],
metadata: [
("department". to_string(), "R&D".to_string()),
("location".to_string(), "Remote".to_string()),
].iter().cloned().collect(),
};
report_tree!(&team);#[derive(StructMem, DeepMem, MemTree)]
struct Config<T> {
value: T,
cached: Option<Vec<String>>,
}
let config: Config<Vec<u32>> = Config {
value: vec![1, 2, 3, 4, 5],
cached: Some(vec!["cache1".to_string(), "cache2".to_string()]),
};
report_tree!(&config);let result = track_deep!({
let mut v = Vec::new();
for i in 0.. 1000 {
v. push(format!("Item {}", i));
}
v
});
println!("Built vector with {} items", result.len());The repository includes a comprehensive example demonstrating all features:
# Clone the repository
git clone https://github.com/StreamIntelligenceLab/struct-mem.git
cd struct-mem
# Run the basic example
cargo run --example basic_testThe example (struct_mem/examples/basic.rs) demonstrates:
- Basic usage of all three traits
- Complex nested structures
- Generic types
- Collection comparisons (Vec vs HashSet)
- Memory tracking during construction
The derive macros work with:
- Primitive types (
u8,i32,f64, etc.) - Standard collections (
Vec,HashMap,HashSet,BTreeMap, etc.) Stringand&strOption<T>andResult<T, E>- Nested structs (that also implement the traits)
- Generic types
- StructMem: Uses
std::mem::size_of: :<T>()to calculate stack size - DeepMem: Recursively calculates heap allocations for collections and owned data
- MemTree: Generates field-by-field breakdowns for detailed analysis
Memory calculations are approximate for heap allocations as they don't account for allocator overhead or internal collection optimizations.
Contributions are welcome! Please feel free to submit issues or pull requests.