【发布时间】:2019-04-13 16:15:26
【问题描述】:
我正在调查一个消耗的内存超出需要的情况。如果我将字符串分配给std::vector,它会突然保留比所需更多的堆内存,即使字符串的大小已知:
以下是我将其分解为:
#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;
}
结果:
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
我希望第 4 行与第 3 行相同。
为什么 libstdc++(这个结果)和 libc++(32/48 字节)都为复制分配分配比复制构造更多的内存?在这两种情况下,新的大小都是已知的。我看不出其中一个在未来更有可能需要额外的内存。
【问题讨论】:
-
虚拟内存很便宜(大多数情况下是免费的)。在有人使用该内存之前,分配内存不会花费您任何费用。例如,Linux 在有人写入之前不会支持任何物理内存分配。因此,如果您只写入 1MB,则分配 128GB 不会产生任何成本。
-
解决您的问题。
-
@JesperJuhl:当然,但这是不同的规模。如果每个字符串花费您 41 而不是 26 个字节,那么该空间将被提交,因为它比页面小得多。在我的情况下(内存数据库),这最终在 1 GB 的数据集上浪费了 300 MB。
-
@Yakk-AdamNevraumont - 你能详细说明一下吗?