【发布时间】:2011-05-04 14:11:43
【问题描述】:
我正在研究一种使用std::queue 的外部排序算法,并且必须仔细限制其内存使用量。我注意到在合并阶段(使用几个固定长度的std::queues),我的内存使用量增加到我预期的大约 2.5 倍。由于std::queue 默认使用std::deque 作为其底层容器,我在std::deque 上运行了一些测试以确定它的内存开销。以下是在 VC++ 9 上运行的结果,在发布模式下,使用 64 位进程:
将 100,000,000 chars 添加到 std::deque 时,内存使用量将增长到 252,216K。注意 100M chars(1 字节)应该占用 97,656K,所以这是 154,560K 的开销。
我用doubles(8 字节)重复测试,发现内存增长到 1,976,676K,而 100M doubles 应该占用 781,250K,开销为 1,195,426K!!
现在我了解到std::deque 通常实现为“块”的链表。如果这是真的,那么为什么开销与元素大小成正比(因为指针大小当然应该固定为 8 个字节)?为什么它这么大?
任何人都可以解释为什么std::deque 使用这么多危险的内存吗?我想我应该将我的std::queue 底层容器切换到std::vector,因为没有开销(假设适当的大小是reserveed)。我认为std::deque 的好处在很大程度上被这样一个事实所抵消,因为它具有如此巨大的开销(导致缓存未命中、页面错误等),并且复制std::vector 元素的成本可能会更少,鉴于整体内存使用量要低得多。这只是微软对std::deque 的错误实现吗?
【问题讨论】:
-
第一个问题。您如何确定内存使用情况。因为有些方法不如其他方法准确。
-
@Martin,我只是观察任务管理器中进程的“峰值工作集”值。
-
如果你编写一个程序来分配 2M 的数据(以块的形式)然后释放它,然后在退出之前等待用户输入它是否表现出相同的行为。即内存上升然后进入稳定状态但不会下降。 PS> 找不到“Peak Working Set”
-
我想我对 Windows 的虚拟内存系统有足够的了解,可以说当内存被释放时(C++ 中的
deleted),它确实会返回给操作系统。在 Windows 中,内存可以“保留”和“提交”。 “峰值工作集”显示了进程在其生命周期内使用的最大物理 RAM 量,当数量不足以需要交换文件时,它等于“提交的”虚拟内存。我已经确认deleteing 内存会导致内存被释放到操作系统,并且工作集大小相应减小。在我的简单测试中,... -
...没有释放内存。内存使用量在循环中稳步增加。与
std::vector不同,它确实会分配一个比现有块更大 的新连续块(这反映在“峰值工作集”和“工作集”之间的差异上),复制元素,然后释放原始文件,std::deque不会发生这种情况。它以 16 字节块的形式增长(由以下帖子确定)并且不会在插入时释放内存。
标签: c++ visual-c++ memory stl