【问题标题】:Can't track down source of huge memory use无法追踪大量内存使用的来源
【发布时间】:2011-10-06 03:26:27
【问题描述】:

这几天我一直在尝试找出内存问题 - 我的程序使用了大约 3GB 的内存,而它应该使用大约 200MB-300MB。 Valgrind 实际上报告它在峰值时使用了大约 300MB,并且没有报告任何内存泄漏。

程序读取输入文件,并将每个唯一单词存储在该文件中。它是多线程的,我一直在使用 4 个线程运行它。我的主要数据来源是:

  • wchar_t 的固定大小数组(共 4MB)
  • 单词和相关值列表之间的映射。这随着输入的大小而增长。如果输入文件中有 1,000,000 个唯一词,则树中将有 1,000,000 个条目。

我正在执行大量的分配和解除分配(使用 new 和 delete)——每个唯一单词至少两个。是否有可能我释放的内存由于某种原因没有被重用,导致程序不断获取越来越多的内存?随着它继续运行,它不断地抓取更多。

总的来说,关于我应该从这里去哪里有什么想法吗?

编辑 1(基于 Graham 的建议): 我将尝试的一种方法是最小化分配。我将在每个线程中使用一个字符串(如果一个单词比这个字符串长,它可能会偶尔增长),但如果我没记错我的代码,这将消除大量的新/删除调用。如果一切顺利,我将剩下:输入缓冲区的一次性分配,每个线程的字符串一次性分配(带有一些重新分配),每个映射条目两个分配(一个用于键,一个用于值)。

谢谢!

【问题讨论】:

  • 格雷厄姆的回答似乎是有效的。您如何确定正在使用多少内存以及正在运行什么操作系统(是 64 位还是 32 位)?您要新建/删除的对象只是数据结构还是成熟的类对象?
  • 我正在使用 Valgrind 和命令 free -m (报告有多少内存是空闲的,当它使用大量内存时给我一个粗略的想法)。这是在 64 位 Linux 上。我已经尝试过使用 std::wstring 和 c 风格的字符串。

标签: c++ memory-management


【解决方案1】:

很可能是堆碎片。因为您正在分配和释放如此大量的小块,所以很可能有大量的小空闲块太小而无法被后续分配重用。由于这些块被有效地浪费了,进程必须不断地从系统中获取越来越多的内存来满足新的分配。

您可以通过首先使用string::reserve() 在每个字符串中保留足够大的默认容量,然后在您完成字符串(而不是删除)时将它们清除为空来减轻这种影响。然后,保留一个空字符串列表以供重复使用,而不是一直分配新字符串。

编辑:上述建议假定分配的对象是std::strings。如果不是,那么您可能仍然可以应用保留旧空对象以供重复使用的一般技术。

【讨论】:

  • 这听起来像是目前最有可能出现的问题,感谢您的意见!用我会尝试的策略编辑了我的原始帖子。
【解决方案2】:

程序释放的内存应该返回到可以再次分配的堆中。

但是,这并不意味着它被释放回操作系统。通常,应用会继续“拥有”已分配和释放的内存。

这是一个 Windows 应用程序吗?你是如何分配和释放内存的?您如何确定应用使用了多少内存?

【讨论】:

  • 如果他使用的是 Valgrind 那就是 linux。
  • 是的,它是使用 gcc 4.4.4 在 Linux 中构建的,我使用 new/delete,使用 valgrind 和 free -m 进行分析
【解决方案3】:

如果可以的话,您应该尝试将资源分配包装到一个类中。在构造函数中调用new,在析构函数中调用delete。尝试并利用范围,以便更自动地完成内存管理。

http://en.wikipedia.org/wiki/RAII

【讨论】:

    猜你喜欢
    • 2012-07-01
    • 2017-05-11
    • 2020-01-01
    • 2011-02-19
    • 2014-08-30
    • 1970-01-01
    • 2020-02-05
    • 1970-01-01
    • 2020-07-03
    相关资源
    最近更新 更多