Rust动态类型大小计算库dyn_size_of的使用,高效获取动态类型内存占用和布局信息
Rust动态类型大小计算库dyn_size_of的使用,高效获取动态类型内存占用和布局信息
dyn_size_of
是由 Piotr Beling 开发的 Rust 库,用于报告变量消耗的近似内存量,包括堆上分配的内存。
简单使用示例
use dyn_size_of::GetSize;
let bs = vec![1u32, 2u32, 3u32].into_boxed_slice();
assert_eq!(bs.size_bytes_dyn(), 3*4); // 仅计算堆内存
assert_eq!(bs.size_bytes(), 3*4 + std::mem::size_of_val(&bs)); // 计算堆内存和栈内存
为自定义类型实现 GetSize
use dyn_size_of::GetSize;
// 不使用堆内存的类型
struct NoHeapMem {
a: u32,
b: u8
}
// 对于不使用堆分配的类型,默认实现即可
impl GetSize for NoHeapMem {}
// 使用堆内存的类型
struct WithHeapMem {
a: Vec<u32>,
b: Vec<u8>,
c: u32
}
// 对于使用堆分配的类型:
impl GetSize for WithHeapMem {
// 必须实现 size_bytes_dyn 并返回堆内存使用量
fn size_bytes_dyn(&self) -> usize {
self.a.size_bytes_dyn() + self.b.size_bytes_dyn()
}
// 必须将 USES_DYN_MEM 设置为 true
const USES_DYN_MEM: bool = true;
}
let s = NoHeapMem { a: 1, b: 2 };
assert_eq!(NoHeapMem::USES_DYN_MEM, false);
assert_eq!(s.size_bytes_dyn(), 0); // 无堆内存
assert_eq!(s.size_bytes(), std::mem::size_of_val(&s)); // 仅栈内存
let d = WithHeapMem { a: vec![1, 2], b: vec![3, 4], c: 5 };
assert_eq!(WithHeapMem::USES_DYN_MEM, true);
assert_eq!(d.size_bytes_dyn(), 2*4 + 2*1); // 堆内存计算
assert_eq!(d.size_bytes(), 2*4 + 2*1 + std::mem::size_of_val(&d)); // 堆+栈内存
完整示例代码
下面是一个更完整的示例,展示了如何使用 dyn_size_of
来计算不同类型的内存使用情况:
use dyn_size_of::GetSize;
fn main() {
// 基本类型示例
let x = 42u32;
println!("u32 size: {} bytes (stack only)", x.size_bytes());
// Vec示例
let vec = vec![1, 2, 3, 4, 5];
println!("Vec<i32> with 5 elements:");
println!(" Heap memory: {} bytes", vec.size_bytes_dyn());
println!(" Total memory: {} bytes", vec.size_bytes());
// String示例
let s = String::from("Hello, dyn_size_of!");
println!("String: '{}'", s);
println!(" Heap memory: {} bytes", s.size_bytes_dyn());
println!(" Total memory: {} bytes", s.size_bytes());
// 自定义类型示例
#[derive(Default)]
struct Person {
name: String,
age: u8,
hobbies: Vec<String>,
}
impl GetSize for Person {
fn size_bytes_dyn(&self) -> usize {
self.name.size_bytes_dyn() + self.hobbies.size_bytes_dyn()
}
const USES_DYN_MEM: bool = true;
}
let person = Person {
name: String::from("Alice"),
age: 30,
hobbies: vec![
String::from("Programming"),
String::from("Reading"),
String::from("Hiking"),
],
};
println!("Person struct:");
println!(" Heap memory: {} bytes", person.size_bytes_dyn());
println!(" Total memory: {} bytes", person.size_bytes());
}
安装方法
在您的项目目录中运行以下 Cargo 命令:
cargo add dyn_size_of
或者将以下行添加到您的 Cargo.toml 中:
dyn_size_of = "0.4.4"
许可证
该库采用 MIT 或 Apache-2.0 双重许可证。
1 回复
Rust动态类型大小计算库dyn_size_of的使用
介绍
dyn_size_of
是一个Rust库,用于高效获取动态类型的内存占用和布局信息。它特别适用于需要处理动态分发类型(dyn Trait
)的场景,能够提供比标准库std::mem::size_of
更详细的内存信息。
主要功能
- 计算动态类型的大小
- 获取类型的内存布局信息
- 支持泛型和trait对象
- 提供对齐信息
安装
在Cargo.toml中添加依赖:
[dependencies]
dyn_size_of = "0.2"
使用方法
基本用法
use dyn_size_of::GetSize;
#[derive(GetSize)]
struct Example {
a: u32,
b: String,
c: Vec<u8>,
}
fn main() {
let example = Example {
a: 42,
b: "hello".to_string(),
c: vec![1, 2, 3],
};
// 获取结构体大小
println!("Size of Example: {}", example.get_size());
// 获取堆分配的大小
println!("Heap size of Example: {}", example.get_heap_size());
}
处理trait对象
use dyn_size_of::{GetSize, get_size_of_val_dyn};
trait MyTrait: GetSize {
fn do_something(&self);
}
#[derive(GetSize)]
struct Impl1 {
data: Vec<i32>,
}
impl MyTrait for Impl1 {
fn do_something(&self) {
println!("Impl1 doing something");
}
}
#[derive(GetSize)]
struct Impl2 {
name: String,
value: f64,
}
impl MyTrait for Impl2 {
fn do_something(&self) {
println!("Impl2 doing something");
}
}
fn main() {
let impl1: Box<dyn MyTrait> = Box::new(Impl1 {
data: vec![1, 2, 3],
});
let impl2: Box<dyn MyTrait> = Box::new(Impl2 {
name: "test".to_string(),
value: 3.14,
});
println!("Size of impl1: {}", get_size_of_val_dyn(&*impl1));
println!("Size of impl2: {}", get_size_of_val_dyn(&*impl2));
}
获取详细布局信息
use dyn_size_of::{GetSize, get_layout_dyn};
#[derive(GetSize)]
struct Detailed {
a: u64,
b: Option<String>,
c: [u8; 16],
}
fn main() {
let detailed = Detailed {
a: 123,
b: Some("layout".to_string()),
c: [0; 16],
};
let layout = get_layout_dyn(&detailed);
println!("{:#?}", layout);
}
高级用法
自定义类型的大小计算
use dyn_size_of::GetSize;
struct Custom {
data: Vec<u8>,
extra: usize,
}
impl GetSize for Custom {
fn get_size(&self) -> usize {
std::mem::size_of_val(self) + self.data.capacity()
}
fn get_heap_size(&self) -> usize {
self.data.capacity()
}
}
fn main() {
let custom = Custom {
data: vec![0; 100],
extra: 42,
};
println!("Total size: {}", custom.get_size());
println!("Heap size: {}", custom.get_heap_size());
}
忽略某些字段
use dyn_size_of::GetSize;
#[derive(GetSize)]
struct WithIgnore {
important: Vec<u32>,
#[ignore_size]
not_important: std::time::Instant,
}
fn main() {
let instance = WithIgnore {
important: vec![1, 2, 3],
not_important: std::time::Instant::now(),
};
println!("Size without ignored field: {}", instance.get_size());
}
性能提示
get_size_of_val_dyn
比直接调用get_size
有额外开销,应避免在性能关键路径频繁使用- 对于已知具体类型的情况,优先使用
get_size
而不是get_size_of_val_dyn
- 考虑缓存计算结果,如果值的大小不会改变
注意事项
- 该库无法准确计算包含原始指针的类型的堆内存使用情况
- 对于循环引用的数据结构,可能导致无限递归
- 计算的大小是近似值,可能与实际内存分配有差异
完整示例demo
以下是一个完整的示例,展示了dyn_size_of
库的主要功能:
use dyn_size_of::{GetSize, get_size_of_val_dyn, get_layout_dyn};
// 基本结构体示例
#[derive(GetSize)]
struct Person {
id: u64,
name: String,
age: u8,
tags: Vec<String>,
}
// 自定义大小的结构体
struct CustomData {
buffer: Vec<u8>,
metadata: String,
}
impl GetSize for CustomData {
fn get_size(&self) -> usize {
std::mem::size_of_val(self) + self.buffer.capacity() + self.metadata.capacity()
}
fn get_heap_size(&self) -> usize {
self.buffer.capacity() + self.metadata.capacity()
}
}
// 带忽略字段的结构体
#[derive(GetSize)]
struct Config {
settings: Vec<String>,
#[ignore_size]
last_updated: std::time::SystemTime,
}
// Trait对象示例
trait DataSource: GetSize {
fn fetch(&self) -> Vec<u8>;
}
#[derive(GetSize)]
struct MemorySource {
data: Vec<u8>,
}
impl DataSource for MemorySource {
fn fetch(&self) -> Vec<u8> {
self.data.clone()
}
}
#[derive(GetSize)]
struct FileSource {
path: String,
cache: Vec<u8>,
}
impl DataSource for FileSource {
fn fetch(&self) -> Vec<u8> {
self.cache.clone()
}
}
fn main() {
// 基本用法
let person = Person {
id: 1,
name: "Alice".to_string(),
age: 30,
tags: vec!["admin".to_string(), "user".to_string()],
};
println!("Person size: {}", person.get_size());
println!("Person heap size: {}", person.get_heap_size());
// 自定义大小
let custom = CustomData {
buffer: vec![0; 1024],
metadata: "sample data".to_string(),
};
println!("Custom data size: {}", custom.get_size());
// 忽略字段
let config = Config {
settings: vec!["dark_mode".to_string(), "notifications".to_string()],
last_updated: std::time::SystemTime::now(),
};
println!("Config size (ignoring timestamp): {}", config.get_size());
// Trait对象
let memory_source: Box<dyn DataSource> = Box::new(MemorySource {
data: vec![1, 2, 3, 4, 5],
});
let file_source: Box<dyn DataSource> = Box::new(FileSource {
path: "/data/sample.bin".to_string(),
cache: vec![0; 512],
});
println!("Memory source size: {}", get_size_of_val_dyn(&*memory_source));
println!("File source size: {}", get_size_of_val_dyn(&*file_source));
// 获取布局信息
let layout = get_layout_dyn(&person);
println!("Person layout: {:#?}", layout);
// 性能提示:缓存已知类型的大小
let person_size = person.get_size();
println!("Cached person size: {}", person_size);
}