问题描述
我正在Rust中基于bplus树构建索引树,到目前为止,父节点的定义如下:
struct Parent<T : std::fmt::Debug> {
subtree_count : [usize; Arity],children : [*mut ParentOrLeaf<T>; Arity],used : usize,}
在我的Arity = 8的64位计算机上,计算得出的总内存需求为136个字节。我正在使用std::alloc::Layout::new
和std::alloc::alloc
分配此结构。但是我担心malloc库比2的幂大一点(136> 128)最终将为此数据结构分配256个字节,而不是仅分配136个字节。由于这是容器类型,浪费了一半的内存分配是不可接受的。
std::alloc::Layout::new::<Parent<T>>().align()
报告的布局为8。
此结构在分配后实际上会占用多少内存?
如果浪费了太多内存,我可以将subtree_count : [usize; Arity]
更改为subtree_count : [usize; Arity-1]
,这将使总内存为128。然后重做我库的所有优化逻辑来处理更改。但是在我这样做之前,我想确保这实际上是必要的。
解决方法
如果大小为136,则意味着数组或向量中许多结构的连续分配将为每个结构使用136个字节。
在单独分配某些结构时,浪费的空间量仅取决于基础的malloc()
策略,而不是所分配类型的属性。
例如,在我的stable-x86_64-unknown-linux-gnu平台上对您的示例进行了快速而肮脏的修改,可以实现以下目的:
size 136
align 8
arr delta1 136
arr delta2 136
box delta1 144
box delta2 144
当然没有保证三个分配的结构彼此靠近,但是在这种特定情况下,它们和浪费(不是真正的浪费,而是由分配器本身使用)空间是8个字节。
struct ParentOrLeaf<T: std::fmt::Debug> {
value: Option<T>,}
const Arity: usize = 8;
struct Parent<T: std::fmt::Debug> {
subtree_count: [usize; Arity],children: [*mut ParentOrLeaf<T>; Arity],used: usize,}
fn main() {
type P = Parent<i32>;
let l = std::alloc::Layout::new::<P>();
println!("size {}",l.size());
println!("align {}",l.align());
let ptr: *mut ParentOrLeaf<i32> = std::ptr::null_mut();
let arr = [
P {
subtree_count: [0; Arity],children: [ptr; Arity],used: 0,},P {
subtree_count: [0; Arity],];
let a0 = &arr[0] as *const P as usize;
let a1 = &arr[1] as *const P as usize;
let a2 = &arr[2] as *const P as usize;
println!("arr delta1 {}",a1 - a0);
println!("arr delta2 {}",a2 - a1);
let p0 = Box::new(P {
subtree_count: [0; Arity],});
let p1 = Box::new(P {
subtree_count: [0; Arity],});
let p2 = Box::new(P {
subtree_count: [0; Arity],});
let a0 = p0.as_ref() as *const P as usize;
let a1 = p1.as_ref() as *const P as usize;
let a2 = p2.as_ref() as *const P as usize;
println!("box delta1 {}",a1 - a0);
println!("box delta2 {}",a2 - a1);
}