【问题标题】:Memory sizes (in bytes) of vector iterator, vector chain, and vector flatten in RustRust 中向量迭代器、向量链和向量展平的内存大小(以字节为单位)
【发布时间】:2022-09-27 15:41:13
【问题描述】:

我有以下示例代码:

let vector_1 = vec![1, 2, 3];
let vector_2 = vec![4, 5, 6];

{ 
  let vector_1_iter = vector_1.iter(); 
}
{ 
  let chained = vector_1.iter().chain(vector_2.iter());
}
{
  let vector_combined = vec![vector_1, vector_2];
  let flatten = vector_combined.iter().flatten();
}

我想知道vector_1_iter 的大小,以字节为单位,以字节为单位。如果我要找到vector_1 和vector_2 的大小,我只需将向量的长度乘以i32 的字节数。但是,我不确定将向量转换为迭代器后大小是否会改变。与链接和展平相同,它们不会占用等于数组的整个长度乘以每种数据类型的大小的相同大小吗?

  • 为什么需要尺寸?还,\"我只取向量的长度并乘以 i32 的字节\"是不正确的。那只是内容的记忆;它周围有一些控制结构(据我所知)占用3*usize 的空间。并且可能会丢失填充。从技术上讲,即使那不是真的,实际尺寸一个向量是它的预订的大小,不一定需要与其内容相匹配。如您所见:它很复杂。
  • std::mem::size_of()可以帮你搞定一些的信息,但它不会告诉你全部的大小包括堆分配,绝对不是任何分配器开销。如果你edit你的问题告诉我们你想用这个号码做什么,也许我们可以给你一个体面的答案。
  • 如果您对堆分配感兴趣,可能想看看 valgrind 的地块或一些ad hoc techniques。

标签: vector rust iterator flatten chaining


【解决方案1】:

Vec 的大小

Vec 是一个结构体,由指向堆上分配的内存区域的指针、容量(显示可以存储在堆内存中的项目总数)和长度(显示当前存储在堆内存中)。

其中每一个都是usize 类型——在 x86_64 架构上占用 8 个字节。

因此,Vec<i32> 占用的总内存实际上是 24 字节 +(容量 x 4)。或者,更一般地说:

std::mem::size_of::<Vec<T>>() + vector_1.capacity() * std::mem::size_of::<T>()

迭代器的大小

请注意:

let vector_1_iter = vector_1.iter(); 

实际上并没有将 vector_1 转换为迭代器 - iter 借用了向量,并返回引用它的 std::slice::Iter。它没有任何额外的堆分配与之相关,我们可以看到它的内存大小是这样的:

println!("size of vector_1_iter {}", std::mem::size_of::<std::slice::Iter<'_, i32>>());

结果是 16 个字节,在我的机器上。

链式迭代器的大小

当我们使用chain 将两个迭代器链接在一起时,两个迭代器都被消耗,并返回一个std::iter::Chain。我们可以再次使用size_of,但是当有多个级别的泛型参数时,这开始变得更加难以表达。相反,我们可以使用std::mem::size_of_val:

let chained = vector_1.iter().chain(vector_2.iter());
println!("size of chained iter {}", std::mem::size_of_val(&chained));

在我的机器上,这会打印 32 - 这是有道理的,因为它包含两个原始迭代器(每个迭代器都是 16 个字节)。

扁平迭代器

我们可以使用相同的方法:

let vector_combined = vec![vector_1, vector_2];
let flatten = vector_combined.iter().flatten();    
println!("size of flattened iter {}", std::mem::size_of_val(&flatten));

这为我打印了48。

Rust Playground


请注意,上面的迭代器都没有消耗它们正在迭代的原始容器。如果您使用了into_iter(),结果将完全不同,因为此方法使用Vec 并返回一个IntoIter 结构——因此它拥有包含Vec 实际内容的堆内存。

另请注意,这些结构的内容和布局是实现细节,因此您不能真正依赖这些大小保持不变。 Vec 有点例外,因为有一些guarantees 关于它的结构。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    • 2021-11-24
    • 1970-01-01
    • 1970-01-01
    • 2017-08-29
    • 2017-03-07
    相关资源
    最近更新 更多