Visual C++矢量擦除增加了内存使用率

Visual C++ vector erase increases memory usage?

本文关键字:内存 使用率 增加 擦除 C++ Visual      更新时间:2023-10-16

这是我在stackoverflow上的第一个问题。我在很大程度上用以下代码行寻找了我所经历的原因:

unsigned long long _mem1= getUsedVirtualMemory();
vector.erase(vector.begin() + _idx);
contained= false; // don't stop the loop
_idx--; // the removed object has redefined the idx to be consider.
_mem1 = getUsedVirtualMemory() - _mem1;
if (_mem1 > 0) printf("Memory - 2 mem1: %lun" , _mem1);

我的程序消耗了大量内存,经过密集的调试、一些打印和耗时的分析,我得出了这一点:

getUsedVirtualMemory使用以下代码实现:

PROCESS_MEMORY_COUNTERS_EX pmc;
GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*) &pmc, sizeof(pmc));
SIZE_T virtualMemUsedByMe = pmc.PrivateUsage;
return virtualMemUsedByMe;

以获得由所述进程分配的虚拟存储器的量;向量是对象(而不是指针)的向量。

在大多数情况下,矢量的擦除方法似乎如预期的那样工作,但在某些情况下,该矢量的擦除方式似乎增加了进程使用的内存,而不是释放它。我在代码周围的许多情况下都使用Windows系统函数GetProcessMemoryInfo来调试这个问题,它似乎返回了使用过的虚拟内存的实际值。

我使用的是Visual Studio C++2010 Professional。

如果需要更多信息,请告诉我。

谢谢你的回复。

更新:

你在回复中写的所有内容都是正确的,我忘记了以下细节:

  1. 我已经知道向量有一个大小(元素的实际数量)和一个容量(分配给存储元素的插槽)
  2. 我已经知道擦除方法不会释放内存(我找了很多关于该方法的文档)
  3. 最后,我稍后会将其他元素添加到该向量中,所以我不需要收缩该向量

实际问题是,在这种情况下,最后一行代码中的"_mem1"值显示出1.600.000字节的差异:内存增加不合理,而我预计为0字节。

此外,在运算后使用的内存值将小于第一个的情况下,我预计会有一个非常大的数字来解释,例如在无符号整数减法定义行为吗?

我得到的不是预期的结果,而是一个大于0但相对较短的值。

为了更好地了解问题的发生率,在这段代码上迭代数千次,意外地分配了大约20 Gb的虚拟内存。

矢量具有:

  • 一个size(),它指示容器中有多少活动元素
  • 一个capacity(),它告诉内存中保留了多少个元素

erase()将大小更改为零。它不会释放分配的内存容量。

您可以使用shrink_to_fit()来确保容量减小到所需大小。

如果需要,用resize()更改大小或用reserve()更改容量可能会增加分配的内存,但如果新的大小/容量低于现有容量,则不一定会释放内存。

这是因为擦除不会释放内存,它只是擦除元素。看看草药。

要(真正)释放你可以做的内存(从参考链接):

正确的方法"收缩到合适";矢量

那么,我们能写一个压缩向量的代码吗;以适应";使得它的容量刚好足以容纳所包含的元素?显然reserve()不能完成这项工作,但幸运的是,确实有一种方法:

vector<Customer>( c ).swap( c );
// ...now c.capacity() == c.size(), or
// perhaps a little more than c.size()

vector.ersase()只能保证从向量中删除元素,不能保证减少底层数组的大小(因为这个过程相当昂贵)。IE:它只将数据清零,不一定会解除分配。

如果你需要一个只有它包含的元素那么大的向量,请尝试使用vector.resize(vector.size())

IIRC在windows上的Debug构建中,new实际上是#defined,而DEBUG_NEW会导致(除其他外)内存块实际上没有被释放,而只是被标记为"已删除"。

你在发布版本中也有同样的行为吗?

问题的一部分可能是std::vector无法从底层内存缓冲区中删除条目,如果它们不在缓冲区的末尾(您的缓冲区不是),那么保留的条目将被移动到一个完全不同的缓冲区。由于您正在擦除第一个元素,所以允许std::vector(因为标准状态是擦除()会使擦除点处/之后的所有迭代器失效,在您的情况下,所有迭代者都会失效)分配一个额外的缓冲区来将剩余元素复制到,然后在复制后丢弃旧的缓冲区。因此,您可能会同时使用两个缓冲区,并且您的内存管理器可能不会将丢弃的缓冲区返回到操作系统,而是保留内存,以便在后续分配中重复使用。这将解释循环迭代中单个的内存使用量增加的原因。