在Rust中,std::vec::shrink_to_fit如何工作?

4

std::vec::shrink_to_fit会分配一个新的、更小的vec.len()数据缓冲区,将数据复制到其中,并销毁旧缓冲区吗?还是它会以某种方式指示内存分配器可以释放缓冲区未初始化的部分,并简单地释放该部分内存?这是否取决于内存分配器?

还有一个离题的问题,我很抱歉在这里问,但如果可能的话,为什么我们不将从向量前面弹出实现为一个简单的“从缓冲区开头释放std::mem::size_of<T>()数量的内存,并将指针增加一”,而不是将所有元素向左移动一个位置呢?

2个回答

6

Vec::shrink_to_fit() 使用 Allocator::shrink() 方法来缩小分配(通过内部 RawVec::shrink_to_fit() 方法),该方法可能只是原地调整现有分配的大小而不移动数据,或者它可能返回一个不同的内存块。

你不能通过重新调整大小来从向量的前面弹出元素,因为内存分配不能改变其起始地址,只能改变其长度。


5
Rust文档的美妙之处在于你可以自己看到!Rust的文档包括整个crate和标准库的源代码,写得非常好,即使你不是Rust专家,也可以阅读它的源代码并理解它(并从中学到很多东西)。所以让我们看看你问题的答案是什么。
  • 在方法Vec::shrink_to_fit的右侧,您可以找到源代码链接
  • 它将我们引导到此方法implementation
  • 在那里,我们在类型为RawVecself.buf上调用shrink_to_fit(self.len)
  • 在左侧的文件树中,我们可以转到raw_vec.rs
  • 在第#357行,我们实现了RawVecshrink_to_fit。它反过来调用下面第#430行实现的RawVec::shrink
  • 在那里,我们最终可以看到在第#442行,该函数调用self.alloc.shrink。这是一个不稳定的Allocator特性上的方法

现在,这个函数可以由不同的分配器以不同的方式实现。有些可能会执行realloc操作,而有些可能会对内存进行实际缩小,并且不会memmove任何内容。要了解您的程序使用的是什么,请了解更多关于您的分配器的信息。

如果您查看分配器的方法,您会发现没有shrink_from_start方法。这是因为该操作并不常见,并且在分配器中实现起来更加困难。这就是为什么使用它来实现Vec::remove(0)没有太多意义的原因。


我实际上尝试过,但在RawVec::shrink之后就放弃了,因为它对我来说嵌套有点太多,也没有寻找alloc.shrink是什么。 - zombiesauce
3
非常详细的答案,这就是我为了尝试回答问题所做的。 :) 没有其他语言/平台像这样拥有如此简单丰富的文档和源代码访问。真的很棒。 - Colin D Bennett

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接