c++ - 在 700,000 个 vector 元素处突然出现内存峰值

标签 c++ memory memory-management vector

所以我在我的程序中运行内存使用测试,我在每个帧中将 20 个元素添加到两个单独的 vector (~60fps)。我预计在某个时候我会开始看到内存泄漏,但内存使用量在某个临界点之前一直保持不变。它总共有大约 700,000 个元素激增,然后在新的高原处再次趋于平稳。

我感觉这与此时自动增加的 vector 分配有关,但我不确定,也无法在网上找到任何信息。它也不能真正解释为什么在那个时候分配了这么多额外的内存(CPU 上的私有(private)字节从 ~800 跃升到~900,系统 GPU 内存从~20 跃升到~140)。以下是 CPU 和 GPU 的 Process Explorer 图表:

enter image description here

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

谁能给我解释一下?

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

enter image description here

总的使用率明显低了很多,但思路是一样的。

最佳答案

当您向一个空 vector 添加一个元素时,它将通过new 为多个元素分配足够的空间。也许像 16 岁。这样做是因为将数组的大小调整到更大的缓冲区很慢,所以它分配的比它需要的多。如果它为 16 个元素分配空间,这意味着您可以在它需要再次调用 new 之前再推迟 15 个。每次它都会显着增长。如果您有 500 个元素(并且它没有空间)并且您再推回一个,它可能会分配 750 个空间。甚至可能是 1000 个。或 2000 个。足够的空间。

事实证明,当您(或 vector )调用 new 时,您会从程序的内存管理器中获取它。如果程序的内存管理器没有足够的可用内存,它会向操作系统请求大量内存,因为操作系统调用本身很慢,而且打乱页面映射也很慢。因此,当 vector 请求 200 字节的空间时,程序的内存管理器可能实际上获取 65536 字节,然后只给 vector 200并保存剩余的 65336 字节以供下一次调用 new。因此,您(或 vector)可以多次调用 new,然后再去打扰操作系统,事情进展得很快。

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

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

我不知道为什么 GPU 的内存会激增,这取决于您对程序执行的操作。但请注意,GPU 内存总量较少,它完全有可能比“私有(private)字节”增长更小

关于c++ - 在 700,000 个 vector 元素处突然出现内存峰值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29401658/

相关文章:

c++ - 使用 Adob​​e Alchemy 的 libFLAC 移植问题

c++ - C++如何将char *精确地转换为double?

c++ - 多线程时一直调用对象析构函数,但对象没有超出范围

java - 从内存中的对象访问静态变量

java - 从 map 中删除后如何从内存中删除对象/实例?

Android - 如何以编程方式跟踪设备上任何正在运行的应用程序的内存使用情况?

c++ - virtual ~T(){} 和 virtual ~T() = default 之间的区别;

c++ - 在堆上分配内存还是传递工作内存?

go - 如何分配内存以映射指向golang中的 slice

ios - 使用 map (苹果或谷歌)的应用程序经常因内存压力而被杀死(主要发生在进入相机时)