在用户定义的类中清空 std::vector 时不释放内存
Memory not released when emptying std::vector inside a user-defined class
当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
模拟类的其余内容。
内存从运行时C++/C 库释放到用户空间内存分配器。通常,这并不意味着用户空间分配器会将此内存返回给操作系统。 用户空间分配器按块从内核分配内存。这些块通过new/malloc进一步根据您的请求进行切片。当您释放/删除此切片块时,它们将返回到用户空间分配器,而不是内核。而当用户空间分配器将能够将分配的内存块返回给内核时,只有用户空间分配器知道。
@user1641854的答案是正确的。这个答案是关于修复它。
有一种相对简单的方法可以解决您的问题。您可以为您的向量提供一个allocator
,该在内部直接要求操作系统提供内存,并在释放时直接将其释放回操作系统。这通常是不可取的,因为直接从操作系统分配通常比设计良好的用户模式堆更慢的分配/释放速度,并且您会在页面末尾浪费一些内存。此外,如果不付出一些努力,它就不会是跨平台的。
话虽如此,您的情况似乎是尝试这是一件合理的事情。
请参阅此处了解如何定义自己的分配器。
然后在Windows上使用::VirtualAlloc
/::VirtualFree
或在Linux上使用mmap
/munmap
用于底层分配/自由函数。
- 当vector是tje全局变量时,c++中vector的内存管理
- 为什么 vector 的随机访问迭代器给出与指针不同的内存地址?
- 使 std::vector 分配对齐内存的现代方法
- 如何为 std::vector 分配内存,然后稍后为某些元素调用构造函数?
- 将 vector<vector<int>> 传递到函数中会产生内存错误
- <char> 使用 Vulkan 映射内存时如何使用 std::vector 而不是 void**?
- C++ 中 std::vector 的内存问题
- vector是否为std::移动的对象连续分配内存
- 释放 std::vector 中指针内存的最有效方法是什么?
- 如何让 'std::vector' <int32_t>从 'std::vector&&' 中获取内存<uint32_t>?
- 访问"std::vector"的保留但未调整大小的内存作为原始内存是否安全?
- 如何使用 std::vector 防止内存重新分配
- 让 'std::vector<unsigned char>' 从 'std::string' 中窃取内存
- 将 std::vector<int> 从原始内存转换为数组
- 给出一个 std::vector 对另一个向量的内存的所有权?
- std::vector<std::vector<int>>:调试断言失败。C++矢量下标超出范围保留内存
- 内存覆盖在我自己的 Vector 类中
- 释放 std::vector 中的内存
- 删除[]是否可以与通用数组正常使用?如果是这样,为什么使用std :: vector ::擦除它会导致释放内存的错误
- vector内存操作中的安全性