无法追踪大量内存使用的来源

Can't track down source of huge memory use

本文关键字:内存 追踪      更新时间:2023-10-16

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

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

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

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

总的来说,你知道我该怎么做吗?

编辑1(基于Graham的建议):我要尝试的一个方法是最小化分配。我将在每个线程中使用一个字符串(如果一个单词比这个字符串长,这个字符串可能会偶尔增长),但如果我没有记错代码,这将消除大量的new/delete调用。如果一切顺利,我将得到:一次性分配输入缓冲区,一次性分配每线程字符串(使用一些reallocs),每个map项分配两次(一次用于key,一次用于value)。

谢谢!

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

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

EDIT:上面的建议假设分配的对象是std::string。如果它们不是,那么您可能仍然可以应用保留旧的空对象以供重用的一般技术。

程序释放的内存应该返回到堆中,在堆中可以重新分配。

然而,这并不意味着它被释放回操作系统。通常,应用程序将继续"拥有"已分配和释放的内存。

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

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

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