这是我在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。
如果需要更多信息,请与我们联系。
感谢您的回复。
更新
您在回复中写的所有内容都是正确的,我忘记了以下详细信息:
实际问题是,在这种情况下,最后一行代码中“_mem1”的值显示1.600.000字节的差异:内存不合理增加,而我预计为0字节。
同样在操作后使用的内存值小于第一个值的情况下,我希望在Is unsigned integer subtraction defined behavior?
中解释的内容非常大。取代预期的结果,我获得的值大于0但相对较短。
为了更好地理解问题的发生率,在该段代码上迭代了数千次,意外地分配了大约20 Gb的虚拟内存。
答案 0 :(得分:4)
向量具有:
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
实际上#defined
为DEBUG_NEW
,这导致(除其他外)内存块实际上没有被释放,而只是标记为' ”中删除。
您是否在发布版本中获得了相同的行为?
答案 4 :(得分:0)
这个难题的一部分可能是std :: vector不能从底层内存缓冲区中删除条目(如果它们不在缓冲区的末尾(你不是),那么保留的条目会被移动 - 可能是一个完全不同的缓冲区。因为你正在擦除第一个元素,所以允许使用std :: vector(因为标准声明erase()使擦除点之后/之后的所有迭代器无效,在你的情况下所有迭代器都会分配附加< / strong>缓冲区将剩余的元素复制到,然后在复制后丢弃旧的缓冲区。因此,您最终可能会同时使用两个缓冲区,并且您的内存管理器可能不会将丢弃的缓冲区返回给操作系统,而是保留内存以便在后续分配中重用它。这可以解释单个循环迭代的内存使用量增加。