Memory 分配此结构时,会浪费多少内存?

Memory 分配此结构时,会浪费多少内存?,memory,memory-management,rust,Memory,Memory Management,Rust,我正在基于Rust中的bplus树构建索引树,到目前为止,我使用了父节点的定义,如: struct Parent<T : std::fmt::Debug> { subtree_count : [usize; Arity], children : [*mut ParentOrLeaf<T>; Arity], used : usize, } 结构父级{ 子树计数:[usize;Arity], 子项:[*mut Paren

我正在基于Rust中的bplus树构建索引树,到目前为止,我使用了父节点的定义,如:

struct Parent<T : std::fmt::Debug> {
    subtree_count : [usize; Arity],
    children      : [*mut ParentOrLeaf<T>; Arity],
    used          : usize, 
}
结构父级{ 子树计数:[usize;Arity], 子项:[*mut ParentOrLeaf;Arity], 用法:usize, } 在我的64位计算机上,Arity=8表示总共需要136字节的内存。我正在使用
std::alloc::Layout::new
std::alloc::alloc
来分配这个结构。但我担心的是,如果malloc库的大小略大于二的幂(136>128),那么它最终将为这个数据结构分配256字节,而不是136字节。由于这是一种容器类型,浪费分配的一半内存是不可接受的

std::alloc::Layout::new::().align()
按预期报告8的布局

这个结构在分配时实际占用多少内存


如果浪费了这么多内存,我可以将
子树计数:[usize;Arity]
更改为
子树计数:[usize;Arity-1]
,这将使总内存达到128。然后重做我的库的所有优化逻辑来处理更改。但是在我这么做之前,我想确定这确实是必要的。

如果大小是136,这意味着数组或向量中许多结构的连续分配将为每个结构恰好使用136字节

在单独分配某些结构时,浪费的空间量仅取决于底层的
malloc()
策略,而不是所分配类型的属性

例如,在我的stable-x86_64-unknown-linux-gnu平台上对您的示例进行快速而肮脏的改编,可以得出以下结论:

136码
对齐8
阿尔德尔塔136
阿尔德尔塔2 136
box delta1 144
博克斯三角洲2 144
当然,不能保证三个分配的结构彼此相邻,但在本例中,它们是相邻的,并且浪费的(不是真正浪费的,而是由分配器本身使用的)空间是8字节

struct ParentOrLeaf{
价值:期权,
}
常数:usize=8;
结构父级{
子树计数:[usize;Arity],
子项:[*mut ParentOrLeaf;Arity],
用法:usize,
}
fn main(){
P型=父母;
让l=std::alloc::Layout::new::

(); println!(“大小{}”,l.size()); println!(“align{}”,l.align()); 让ptr:*mut ParentOrLeaf=std::ptr::null_mut(); 设arr=[ P{ 子树计数:[0;算术], 儿童:[ptr;Arity], 使用:0, }, P{ 子树计数:[0;算术], 儿童:[ptr;Arity], 使用:0, }, P{ 子树计数:[0;算术], 儿童:[ptr;Arity], 使用:0, }, ]; 设a0=&arr[0]为*常数P为usize; 设a1=&arr[1]as*const P as usize; 设a2=&arr[2]as*const P as usize; println!(“arr delta1{}”,a1-a0); println!(“arr delta2{}”,a2-a1); 设p0=Box::new(P{ 子树计数:[0;算术], 儿童:[ptr;Arity], 使用:0, }); 设p1=Box::new(P{ 子树计数:[0;算术], 儿童:[ptr;Arity], 使用:0, }); 设p2=Box::new(P{ 子树计数:[0;算术], 儿童:[ptr;Arity], 使用:0, }); 设a0=p0.as_ref()as*const P as usize; 设a1=p1.as_ref()as*const P as usize; 设a2=p2.as_ref()as*const P as usize; println!(“长方体delta1{}”,a1-a0); println!(“盒形三角洲2{}”,a2-a1); }


我假设默认情况下强制执行数据对齐,因此136字节(最多256字节)的填充很有可能是一种解决方法,您可以删除
已使用的
字段,并依赖父级的
子树计数
中的相应值?这不是对齐问题,因为通常使用该术语。在典型的64位机器上,
Parent
的对齐方式仅为8,而不是128。而是分配器如何管理空间的问题。@AlexLarionov bplus索引树的本质是使用是必要的,但您可以使用父节点所说的来确定最后一个子树计数此顶点的子树总数。这当然取决于您使用的分配器,但我怀疑它最终会分配大量多余的内存。除了有效负载之外,分配的内存块将始终包含一些元数据,例如块的大小。我似乎记得glibc总是分配8字节的倍数,这样你就不会在你的数据结构中浪费任何内存。嗯,看来它消耗的内存高达144字节,所以8字节的浪费空间浪费了6%的空间。8字节不是“浪费的”——它们是分配器使用的元数据,没有办法避免它们。@DanielV是的,但是,正如代码前面所述,只有在这个特定的案例和我的平台上。没有保证。我的意思是,你可以只为这个精确大小的对象编写自己的分配器,在这种情况下,你可以使用更少的元数据,但当使用通用分配器时,你不可能做得更好。@SvenMarnach是的,当然,我的意思是«从应用程序的角度来看»,不是系统。