[英]Why does std::vector::operator= overallocate memory?
I am investigating a case where way more memory is consumed than needed.我正在调查一个案例,其中消耗的内存比需要的多。 If I assign a string to an std::vector
, it suddenly reserves more heap memory than needed, even though the size of the string is already known:如果我将一个字符串分配给std::vector
,它会突然保留比所需更多的堆内存,即使字符串的大小已经知道:
Here's what I broke it down to:这是我将其分解为:
#include <vector>
#include <iostream>
#include <new>
void* operator new(size_t size) {
void * p = malloc(size);
std::cout << "\talloc " << size << " @ " << p;
return p;
}
void operator delete(void* p) {
std::cout << "\t free " << p;
free(p);
}
int main() {
{
std::cout << std::endl << "1. Create first string: ";
auto s1 = std::string{"String with 20 chars"};
std::cout << std::endl << "2. Create longer string: ";
auto s2 = std::string{"String with 25 characters"};
std::cout << std::endl << "3. Copy construct: ";
auto s3 = s2;
std::cout << std::endl << "4. Copy assign: ";
s1 = s3;
std::cout << std::endl << "5. Leaving scope: ";
}
std::cout << std::endl;
}
Result:结果:
1. Create first string: alloc 21 @ 0x56047f176280
2. Create longer string: alloc 26 @ 0x56047f1762a0
3. Copy construct: alloc 26 @ 0x56047f1762d0
4. Copy assign: alloc 41 @ 0x56047f176300 free 0x56047f176280
5. Leaving scope: free 0x56047f1762d0 free 0x56047f1762a0 free 0x56047f176300
I would expect line 4 to be the same as line 3.我希望第 4 行与第 3 行相同。
Why do both libstdc++ (this result) and libc++ (32/48 bytes) allocate more memory for a copy assignment than for a copy construction?为什么 libstdc++(这个结果)和 libc++(32/48 字节)为复制赋值分配的内存比为复制构造分配的内存多? In both cases, the new size is known.在这两种情况下,新的大小都是已知的。 I can't see how one of those is more likely to require additional memory in the future.我看不出其中之一在未来更有可能需要额外的内存。
I tracked it down in the basic_string implementation of libstdc++.我在 libstdc++ 的 basic_string 实现中找到了它。 operator=(const basic_string&)
calls this->assign
, which calls _M_assign
, which calls _M_create
with the new (minimal) and the old capacity. operator=(const basic_string&)
调用this->assign
,后者调用_M_assign
,后者使用新(最小)和旧容量调用_M_create
。 Here, the original capacity is doubled.在这里,原始容量增加了一倍。 A link to the exponential growth policy is included as a comment.指数增长政策的链接包含在评论中。
First, I did not understand how this is related to my example.首先,我不明白这与我的例子有什么关系。 After all, I just want to replace a value.毕竟,我只想替换一个值。
The growth policy for operator=(const basic_string&)
makes more sense when, instead of a single assignment, you consider this code:当您考虑以下代码而不是单个赋值时, operator=(const basic_string&)
的增长策略更有意义:
std::string s;
for (auto i = 100; i < 110; ++i) s = s + std::to_string(i);
Here, setting the capacity so that it is "just fitting" would violate the linear growth requirement.在这里,将容量设置为“恰到好处”将违反线性增长要求。
To solve the memory consumption problem, I now call shrink_to_fit()
on the target string.为了解决内存消耗问题,我现在在目标字符串上调用shrink_to_fit()
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.