内存分配优化
问题
如何减少 Rust 程序的堆分配?
答案
常见优化技巧
// 1. 预分配容量
// ❌ 多次扩容
let mut v = Vec::new();
for i in 0..1000 {
v.push(i); // 可能触发多次 realloc
}
// ✅ 一次分配
let mut v = Vec::with_capacity(1000);
for i in 0..1000 {
v.push(i); // 无 realloc
}
// 2. 用栈代替堆
// ❌ 堆分配
let data: Box<[u8; 64]> = Box::new([0u8; 64]);
// ✅ 栈分配
let data = [0u8; 64];
// 3. 复用 String/Vec 缓冲区
let mut buf = String::with_capacity(256);
for item in items {
buf.clear(); // 清空但保留容量
write!(buf, "item: {}", item).unwrap();
process(&buf);
}
// 4. 使用 SmallVec(小数据栈上,大数据堆)
use smallvec::SmallVec;
let mut v: SmallVec<[i32; 8]> = SmallVec::new();
// 8 个以内在栈上,超过才堆分配
减少分配的常见模式
| 模式 | 说明 |
|---|---|
Vec::with_capacity | 预分配 |
String::with_capacity | 预分配字符串 |
SmallVec / arrayvec | 小数据栈分配 |
&str 代替 String | 引用而非拥有 |
Cow<str> | 按需分配 |
| 对象池 | crossbeam::epoch |
常见面试问题
Q1: 如何检测程序的堆分配次数?
答案:
// 方法 1:dhat 分析器(详见性能分析章节)
#[global_allocator]
static ALLOC: dhat::Alloc = dhat::Alloc;
// 方法 2:自定义分配器统计
use std::alloc::{GlobalAlloc, System, Layout};
use std::sync::atomic::{AtomicUsize, Ordering};
static ALLOC_COUNT: AtomicUsize = AtomicUsize::new(0);
struct CountingAllocator;
unsafe impl GlobalAlloc for CountingAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
ALLOC_COUNT.fetch_add(1, Ordering::Relaxed);
unsafe { System.alloc(layout) }
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
unsafe { System.dealloc(ptr, layout) }
}
}