无法追踪大量内存使用的来源
Can't track down source of huge memory use
几天来我一直在试图追踪一个内存问题——我的程序使用了大约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- 将字符串存储在c++中的稳定内存中
- C++ 指针的内存地址和指向数组的内存地址如何相同?
- Win32编译器选项和内存分配
- 当vector是tje全局变量时,c++中vector的内存管理
- 带内存和隔离功能的SQLite
- 是否可以通过C++扩展强制多个python进程共享同一内存
- 迭代时从向量和内存中删除对象
- 在C++中打印指向不同基元数据类型的指针的内存地址
- 这个指针和内存代码打印是什么?我不知道是打印垃圾还是如何打印我需要的值
- 多个文件的内存分配错误"在抛出 'std :: bad_alloc' what (): std :: bad_alloc 的实例后终止调用" [C++]
- 为什么示例代码访问IUnknown中已删除的内存
- 如何在C++类内存结构中创建"spacer"?
- 从构造函数抛出异常时如何克服内存泄漏
- malloc() 可能出现内存泄漏
- 如何理解将半精度指针转换为无符号长指针和相关的内存对齐
- 在调用FreeLibrary后,释放动态链接到具有相同版本的CRT堆的DLL的内存
- 如何针对特定情况调试和修复此双自由内存损坏问题
- 类型总是使用其大小存储在内存中吗
- C++:光线追踪器导致内存不足错误 - 由于反复调用"new"?
- 无法追踪大量内存使用的来源