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

huangapple go评论74阅读模式
英文:

How does std::vec::shrink_to_fit work in Rust?

问题

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

此外,一个离题的问题,我很抱歉在这里提出,如果这是可能的,为什么我们不例如将从向量的前面弹出实现为“释放std::mem::size_of<T>()内存量的简单操作,然后递增我们的指针一个单位”,而不是将所有元素都向前移动一个单位?

英文:

Does std::vec::shrink_to_fit allocate a new, smaller vec.len() buffer of data, copy to it, and destruct the old buffer, or does it somehow indicate to the memory allocator that the uninitialised part of the buffer can be de-allocated, and simply release that part of the memory? Is that even possible? Does that depend on the memory allocator?

And a tangential question which I apologise to ask here, but if that's possible, why don't we, for example, implement popping from the front of a vector as a simple "release std::mem::size_of<T>() amount of memory from the start of the buffer, and increment our pointer by one", rather than shifting all our elements by one?

答案1

得分: 6

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

您不能通过重新调整大小来从矢量的前面弹出,因为内存分配的起始地址无法更改,只能更改其长度。

英文:

The Vec::shrink_to_fit() uses the Allocator::shrink() method to shrink the allocation (via the internal RawVec::shrink_to_fit(), method which may simply resize the existing allocation in-place without moving the data, or it might return a different memory block.

You can't pop from the front of a vector by re-sizing it, because memory allocations can't have their start address changed, only their length.

答案2

得分: 5

Rust的文档非常美妙,您可以自己查看!Rust的文档包括整个crate和标准库的源代码,编写得非常出色,即使您不是Rust专家,也可以阅读它的源代码并理解它(并从中学到很多东西)。

所以,让我们看看对于您的问题的答案。

  • Vec::shrink_to_fit方法的右侧,您可以找到源代码的链接。
  • 它引导我们到这个方法的实现
  • 在那里,我们在self.buf上调用shrink_to_fit(self.len),它的类型是RawVec
  • 在左侧的文件树中,我们可以转到raw_vec.rs
  • 在第#357行,我们有RawVecshrink_to_fit实现。它反过来调用了下面的第#430行上实现的RawVec::shrink方法。
  • 在那里,我们最终可以看到,在第#442行,此函数调用了self.alloc.shrink。这是不稳定的Allocator trait上的方法

现在,这个函数可以由不同的分配器以不同的方式实现。某些分配器可能会进行realloc,而某些分配器可能会实际收缩内存并且不会memmove任何内容。要查看您的程序使用的是哪个,您必须更多地了解您的分配器。

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

英文:

The beautiful thing about rust's documentation is that you can see for yourself! Rust's documentation includes the source code of whole crate and standard library is written very well and you can read it's source code and understand it (and learn a lot from it) even if you are not rust guru.

So let's see what is the answer to your question.

  • To the right of method Vec::shrink_to_fit you have a link to source code
  • It directs us to this method implementation
  • there we are calling shrink_to_fit(self.len) on self.buf which is of type RawVec
  • In the file tree on the left we can go to raw_vec.rs
  • On line #357 we have implementation of shrink_to_fit for RawVec. It in turn calls RawVec::shrink which is implemented below on line #430
  • There we can finally see that on line #442 this function calls self.alloc.shrink. It is a method on unstable Allocator trait

Now this function can be implemented in different ways by different allocators. Some might do a realloc, and some might perform actual shrinking of the memory and do not memmove anything. To see what your program uses you must learn more about your allocator.

If you look at Allocator's methods you will see that there is no method shrink_from_start. This is because that operation isn't a common one and would be much harder to implement in an allocator. That's why using it to implement Vec::remove(0) wouldn't have much sense.

huangapple
  • 本文由 发表于 2023年5月23日 01:00:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/76308441.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定