Visual C ++矢量擦除会增加内存使用量吗?

时间:2014-12-10 17:44:39

标签: c++ visual-studio-2010 memory vector erase

这是我在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: %lu\n" , _mem1);

我的程序中有大量的内存消耗,经过密集的调试会话,一些printfs和耗时的分析后,我到了这一点:

使用以下代码实现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. 最后,我稍后会向该向量添加其他元素,因此我不需要缩小该向量。
  4. 实际问题是,在这种情况下,最后一行代码中“_mem1”的值显示1.600.000字节的差异:内存不合理增加,而我预计为0字节。

    同样在操作后使用的内存值小于第一个值的情况下,我希望在Is unsigned integer subtraction defined behavior?

    中解释的内容非常大。

    取代预期的结果,我获得的值大于0但相对较短。

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

5 个答案:

答案 0 :(得分:4)

向量具有:

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

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

您可以使用 shrink_to_fit() ,以确保容量减少到适当的大小。

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

答案 1 :(得分:3)

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

要(真的)释放你可以做的记忆(来自参考链接):

  

正确的“收缩适合”矢量或deque

     

那么,我们是否可以编写缩小矢量“适合”的代码,以便其容量足以容纳所包含的元素?显然reserve()不能胜任这项工作,但幸运的是确实有办法:

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

答案 2 :(得分:0)

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

如果您需要的矢量只与其中包含的元素一样大,请尝试使用vector.resize(vector.size())

答案 3 :(得分:0)

IIRC在Windows上的Debug构建中,new实际上#definedDEBUG_NEW,这导致(除其他外)内存块实际上没有被释放,而只是标记为' ”中删除。

您是否在发布版本中获得了相同的行为?

答案 4 :(得分:0)

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