C++ 700000个矢量元素的突然内存峰值

C++ 700000个矢量元素的突然内存峰值,c++,memory,memory-management,vector,C++,Memory,Memory Management,Vector,所以我在我的程序中运行了一个内存使用测试,我在每个帧(约60fps)的两个独立向量中分别添加了20个元素。我希望在某个时候我会开始看到内存泄漏,但相反,内存使用率保持不变,直到某个临界点。大约700000个元素的总量达到峰值,然后在新高原再次趋于平稳 我有一种感觉,这和向量的分配在那个点上自动增加有关,但我不确定,也不能在网上找到任何东西。它也不能真正解释为什么在那个时候分配了这么多额外的内存(CPU上的私有字节从~800跳到~900,系统GPU内存从~20跳到~140)。以下是CPU和GPU的

所以我在我的程序中运行了一个内存使用测试,我在每个帧(约60fps)的两个独立向量中分别添加了20个元素。我希望在某个时候我会开始看到内存泄漏,但相反,内存使用率保持不变,直到某个临界点。大约700000个元素的总量达到峰值,然后在新高原再次趋于平稳

我有一种感觉,这和向量的分配在那个点上自动增加有关,但我不确定,也不能在网上找到任何东西。它也不能真正解释为什么在那个时候分配了这么多额外的内存(CPU上的私有字节从~800跳到~900,系统GPU内存从~20跳到~140)。以下是CPU和GPU的Process Explorer图表:

注意:CPU和GPU使用率的下降是因为我在看到峰值后暂停了程序

谁能给我解释一下吗

编辑:这里有一个更简单、更通用的测试:

总体使用率显然要低很多,但想法是一样的。

向量大小和容量 通过分配比以往任何时候都需要的更多内存来获得良好的性能

大小() 返回当前元素数

空的() 返回容器是否为空(相当于0==size(),但速度更快)

容量() 返回无需重新分配的最大可能元素数

储备(个) 如果容量还不够,可以扩大容量

向量的容量很重要,因为 重新分配使元素的所有引用、指针和迭代器无效。 通过将所有元素移动到新的堆位置,重新分配需要时间。 重新分配大小增量取决于实际的向量实现

使用保留(num)的代码示例:

std::vector v1;//创建一个空向量
v1.储备(80);//为80个元素保留内存

将一个元素添加到空向量时,它将通过
new
为多个元素分配足够的空间。大概16岁吧。之所以这样做,是因为将数组调整为更大的缓冲区的速度很慢,因此它分配的缓冲区比需要的要多。如果它为16个元素分配了空间,这意味着您可以在它需要再次调用
new
之前再向后推15个元素。每一次它都会显著增长。如果您有500个元素(并且它不在房间内),并且您再推回一个元素,它可能会为750个元素分配空间。甚至可能1000。或2000年。有足够的空间

事实证明,当您(或向量)调用
new
时,您可以从程序的内存管理器中获得此信息。如果程序的内存管理器没有足够的可用内存,它将要求操作系统提供大量内存,因为操作系统调用本身很慢,而处理页面映射也很慢。因此,当
vector
要求为
200
字节留出空间时,程序的内存管理器实际上可能会抓取65536字节,然后只给向量其中的200个,并将剩余的65336字节保存起来,以便下次调用
new
。正因为如此,您(或vector)可以多次调用
new
,然后才不得不再次干扰操作系统,事情进展得很快

但这有一个副作用:操作系统实际上无法判断程序实际使用了多少内存。它只知道你从中分配了65536,所以它报告说。当您推回向量中的元素时,向量最终会耗尽容量,并向程序的内存管理器请求更多内容。当它越来越多地这样做时,操作系统报告相同的内存使用情况,因为它看不见。最终,内存管理器的容量耗尽,并要求操作系统提供更多的内存。操作系统分配了另一个巨大的块(65536?131072?),您会看到内存使用量突然大幅增加

发生这种情况的向量大小没有设置,它取决于还分配了什么,以及分配和取消分配的顺序。即使你删除的东西仍然会影响事情,这是非常复杂的。此外,vector的增长速度取决于您的库实现,程序的内存管理器从操作系统获取的内存量也取决于我不知道的因素


我不知道为什么GPU的内存会突然增加,这取决于你在用你的程序做什么。但请注意,GPU内存总量较少,完全有可能其增长量小于“专用字节”。

向量使用动态分配的数组存储其元素。此数组可能需要重新分配,以便在插入新元素时增加大小,这意味着分配一个新数组并将所有元素移动到该数组中。就处理时间而言,这是一项相对昂贵的任务,因此,向量不会在每次将元素添加到容器时重新分配。相反,向量容器可能会分配一些额外的存储以适应可能的增长,因此容器的实际容量可能大于严格要求的存储容量,以容纳其元素(即其大小)。这就解释了你的高原。通过将当前容量加倍来扩大容量。在有限的倍增次数后,其容量可能会翻两番。这可以解释你的扣球

如果您确定这不是内存泄漏,那么最好的方法是保留程序可以达到的最大值的向量。这取决于您正在使用的工具,但可能与您的应用程序请求新内存页文件的分配有关(因为并不是每一次分配都能真正改变应用程序页面文件的内存大小)。@Tony J我的程序不需要在向量中包含这么多元素。我只是对memo有点好奇
std::vector<int> v1;  // Create an empty vector    
v1.reserve(80);       // Reserve memory for 80 elements