当std::vector
是一个类的字段时,我们遇到了一些内存问题。我们在这个向量中填充了大量数据,这些数据需要在程序的某个点上发布。但是,即使向量容量为零,内存也不会被释放或完全释放。
这里有一个我们程序的简化版本。如您所见,课程Foo
只有一个字段:std::vector<int>
。如果我们创建一个std::vector<Foo>
并用Foo
个对象填充它,当我们清空每个对象中的向量时,内存不会完全释放。
我们使用活动监视器测量了内存使用情况,您可以在每个日志行旁边看到每个阶段使用的字节数。此外,我们添加了另一个版本,我们不使用类Foo
对象,在这种情况下,内存完美释放。
#include <iostream>
#include <vector>
class Foo {
public:
std::vector<int> container;
};
int main() {
int n1 = 1000;
int n2 = 100000;
{
std::vector<Foo> foos;
std::cerr << "starting" << std::endl; // 160 KiB
std::cin.get();
for (int i = 0; i < n1; i++){
Foo foo;
foo.container.assign(n2, 666);
foos.push_back(foo);
}
std::cerr << "foos filled" << std::endl; // 382.1 MiB
std::cin.get();
for (unsigned int i = 0; i < foos.size(); i++){
std::vector<int>().swap(foos[i].container);
}
std::cerr << "foos emptied" << std::endl; // 195.7 MiB
std::cin.get();
}
std::cerr << "foos destroyed?" << std::endl; // 296 KiB
std::cin.get();
{
std::vector<std::vector<int> > foos;
std::cerr << "starting" << std::endl; // 296 KiB
std::cin.get();
{
std::vector<int> aux;
aux.assign(n2, 666);
foos.assign(n1, aux);
}
std::cerr << "foos filled" << std::endl; // 382.1 MiB
std::cin.get();
for (unsigned int i = 0; i < foos.size(); ++i) {
std::vector<int>().swap(foos[i]);
}
std::cerr << "foos emptied" << std::endl; // 708 KiB
std::cin.get();
}
std::cerr << "foos destroyed?" << std::endl; // 708 KiB
std::cin.get();
return 0;
}
如果有帮助,我们在Ubuntu 14.04 64位下使用g ++ 4.8.4。具体的内存占用率取决于我们是使用C ++ 11还是C ++ 98,但两种情况都会出现相同的现象。
关于发生了什么以及如何恢复记忆的任何想法,如果需要的话,强行要求?
编辑:请注意,当我们销毁Foo
类的所有对象时,确实会返回内存,但在我们的实际问题中,我们仍然需要Foo
的其他内容 - 模拟类。
答案 0 :(得分:10)
内存从运行时C ++ / C库发布到用户空间内存分配器。通常,它并不意味着用户空间分配器会将此内存返回给操作系统。用户空间分配器按块从内核分配内存。通过new / malloc对您的请求进一步细化。当您释放/删除此切片块时,它们将返回到用户空间分配器,而不是内核。并且当用户空间分配器将能够将分配的内存块返回到内核时,仅由用户空间分配器知道。
答案 1 :(得分:3)
@ user1641854的回答是正确的,为什么会发生这种情况。这个答案是关于修复它。
有一个相对简单的方法来解决您的问题。你可以给你的向量allocator
,它在内部直接向操作系统询问内存,并在释放时将其直接释放回操作系统。这通常是不合需要的,因为直接来自OS分配通常比设计良好的用户模式堆更慢地分配/释放,并且您将在页面末尾浪费一些内存。此外,如果不付出一些努力,它就不会是跨平台的。
说过你的案子似乎是一个合理的尝试。
请参阅here了解如何定义自己的分配器。
然后在Windows上使用::VirtualAlloc
/ ::VirtualFree
或在linux上使用mmap
/ munmap
获取基础分配/免费功能。