在 700,000 个矢量元素处突然出现内存峰值
Sudden memory spike at 700,000 vector elements
所以我在我的程序中 运行 进行了内存使用测试,其中我将 20 个元素分别添加到每帧的两个独立向量中 (~60fps)。我预计在某个时候我会开始看到内存泄漏,但内存使用量在某个临界点之前一直保持不变。它总共有大约 700,000 个元素激增,然后在新的高原处再次趋于平稳。
我感觉这与此时自动增加的向量分配有关,但我不确定并且无法在网上找到任何内容。它也不能真正解释为什么在那个时候分配了这么多额外的内存(CPU 上的私有字节从 ~800 跃升到~900,系统 GPU 内存从~20 跃升到~140)。以下是 CPU 和 GPU 的 Process Explorer 图:
注意:CPU 和 GPU 使用率的下降是因为我在看到峰值后暂停了程序。
谁能给我解释一下?
编辑:这是一个更简单、更通用的测试:
总使用率明显低了很多,但思路是一样的。
矢量大小和容量
通过分配比以往更多的内存来获得良好的性能。
尺寸()
Returns当前元素个数
空()
Returns容器是否为空(相当于0==size()但速度更快)
容量()
Returns无需重新分配的最大可能元素数
储备(数量)
扩大容量,如果容量还不够
向量的容量很重要,因为
重新分配会使元素的所有引用、指针和迭代器失效。
通过将所有元素移动到新的堆位置,重新分配需要时间。
重新分配大小增量取决于实际向量实现。
使用reserve(num)的代码示例:
std::vector<int> v1; // Create an empty vector
v1.reserve(80); // Reserve memory for 80 elements
当您向空向量添加元素时,它会通过 new
为多个元素分配足够的 space。也许像 16 岁。这样做是因为将数组的大小调整到更大的缓冲区很慢,所以它分配的比它需要的多。如果它为 16 个元素分配空间,这意味着您可以在它需要再次调用 new
之前再推回 15 个。每次它都会显着增长。如果您有 500 个元素(并且它没有空间)并且您再推回一个,它可能会分配 750 个空间。甚至可能是 1000 个。或 2000 个。足够的空间。
事实证明,当您(或向量)调用 new
时,您会从程序的内存管理器中获取它。如果程序的内存管理器没有足够的可用内存,它会向操作系统请求大量内存,因为操作系统调用本身很慢,而且打乱页面映射也很慢。因此,当 vector
请求 200
字节的空间时,程序的内存管理器可能 实际上 抓取 65536 字节,然后只给向量其中的 200 个字节,并且为下一次调用 new
保存剩余的 65336 字节。因此,您(或 vector)可以调用 new
很多次,然后再去打扰操作系统,事情进展得很快。
但这有一个副作用:操作系统实际上无法判断您的程序真正使用了多少内存。它只知道你从它那里分配了 65536,所以它会报告。当您将向量中的元素推回时,最终 向量会耗尽容量,并向程序的内存管理器请求更多。随着它越来越多地这样做,操作系统报告相同的内存使用情况,因为它看不到。 最终 内存管理器用完容量,并向操作系统请求更多。操作系统分配了另一个巨大的块(65536?131072?),您会看到内存使用量突然大幅上升。
未设置发生这种情况的向量大小,它取决于还分配了什么,以及分配和释放它们的顺序。即使是您 delete
所做的事情仍然会影响事情,这非常复杂。此外,vector 的增长速度取决于你的库实现,程序的内存管理器从 OS 中获取的内存量也取决于我不知道的因素。
我不知道为什么 GPU 的内存会激增,这取决于您对程序执行的操作。但请注意,GPU 内存总量较少,它完全有可能比 "private bytes".
增长 更小 数量
向量使用动态分配的数组来存储它们的elements.This数组可能需要重新分配以便在插入新元素时增加大小,这意味着分配一个新数组并移动它的所有元素。就处理时间而言,这是一项相对昂贵的任务,因此,每次将元素添加到容器时,向量不会重新分配。相反,矢量容器可能会分配一些额外的存储空间以适应可能的增长,并且因此容器的实际容量可能大于包含其元素(即其大小)所严格需要的存储空间 . 这解释了你的高原。容量扩大是通过将当前容量增加一倍来完成的。可能是这样的情况,在有限次数的翻倍之后,它的容量翻了两番。 这将解释您的峰值。
所以我在我的程序中 运行 进行了内存使用测试,其中我将 20 个元素分别添加到每帧的两个独立向量中 (~60fps)。我预计在某个时候我会开始看到内存泄漏,但内存使用量在某个临界点之前一直保持不变。它总共有大约 700,000 个元素激增,然后在新的高原处再次趋于平稳。
我感觉这与此时自动增加的向量分配有关,但我不确定并且无法在网上找到任何内容。它也不能真正解释为什么在那个时候分配了这么多额外的内存(CPU 上的私有字节从 ~800 跃升到~900,系统 GPU 内存从~20 跃升到~140)。以下是 CPU 和 GPU 的 Process Explorer 图:
注意:CPU 和 GPU 使用率的下降是因为我在看到峰值后暂停了程序。
谁能给我解释一下?
编辑:这是一个更简单、更通用的测试:
总使用率明显低了很多,但思路是一样的。
矢量大小和容量
通过分配比以往更多的内存来获得良好的性能。
尺寸()
Returns当前元素个数
空()
Returns容器是否为空(相当于0==size()但速度更快)
容量()
Returns无需重新分配的最大可能元素数
储备(数量)
扩大容量,如果容量还不够
向量的容量很重要,因为 重新分配会使元素的所有引用、指针和迭代器失效。 通过将所有元素移动到新的堆位置,重新分配需要时间。 重新分配大小增量取决于实际向量实现。
使用reserve(num)的代码示例:
std::vector<int> v1; // Create an empty vector
v1.reserve(80); // Reserve memory for 80 elements
当您向空向量添加元素时,它会通过 new
为多个元素分配足够的 space。也许像 16 岁。这样做是因为将数组的大小调整到更大的缓冲区很慢,所以它分配的比它需要的多。如果它为 16 个元素分配空间,这意味着您可以在它需要再次调用 new
之前再推回 15 个。每次它都会显着增长。如果您有 500 个元素(并且它没有空间)并且您再推回一个,它可能会分配 750 个空间。甚至可能是 1000 个。或 2000 个。足够的空间。
事实证明,当您(或向量)调用 new
时,您会从程序的内存管理器中获取它。如果程序的内存管理器没有足够的可用内存,它会向操作系统请求大量内存,因为操作系统调用本身很慢,而且打乱页面映射也很慢。因此,当 vector
请求 200
字节的空间时,程序的内存管理器可能 实际上 抓取 65536 字节,然后只给向量其中的 200 个字节,并且为下一次调用 new
保存剩余的 65336 字节。因此,您(或 vector)可以调用 new
很多次,然后再去打扰操作系统,事情进展得很快。
但这有一个副作用:操作系统实际上无法判断您的程序真正使用了多少内存。它只知道你从它那里分配了 65536,所以它会报告。当您将向量中的元素推回时,最终 向量会耗尽容量,并向程序的内存管理器请求更多。随着它越来越多地这样做,操作系统报告相同的内存使用情况,因为它看不到。 最终 内存管理器用完容量,并向操作系统请求更多。操作系统分配了另一个巨大的块(65536?131072?),您会看到内存使用量突然大幅上升。
未设置发生这种情况的向量大小,它取决于还分配了什么,以及分配和释放它们的顺序。即使是您 delete
所做的事情仍然会影响事情,这非常复杂。此外,vector 的增长速度取决于你的库实现,程序的内存管理器从 OS 中获取的内存量也取决于我不知道的因素。
我不知道为什么 GPU 的内存会激增,这取决于您对程序执行的操作。但请注意,GPU 内存总量较少,它完全有可能比 "private bytes".
增长 更小 数量向量使用动态分配的数组来存储它们的elements.This数组可能需要重新分配以便在插入新元素时增加大小,这意味着分配一个新数组并移动它的所有元素。就处理时间而言,这是一项相对昂贵的任务,因此,每次将元素添加到容器时,向量不会重新分配。相反,矢量容器可能会分配一些额外的存储空间以适应可能的增长,并且因此容器的实际容量可能大于包含其元素(即其大小)所严格需要的存储空间 . 这解释了你的高原。容量扩大是通过将当前容量增加一倍来完成的。可能是这样的情况,在有限次数的翻倍之后,它的容量翻了两番。 这将解释您的峰值。