C++中的内存分配分析

54

我正在编写一个应用程序,惊讶地发现它的总内存使用量已经太高了。 我想对我的应用程序进行动态内存使用分析:堆中有多少个各种类型的对象,以及创建这些对象的函数是哪些?此外,每个对象使用了多少内存?

有没有简单的方法可以做到这一点?我在Linux和Windows上都在工作,所以任何一个平台的工具都可以。

注意:我在这里不关心内存泄漏。

12个回答

25

你有试过Valgrind吗?它是Linux的一款性能分析工具。它有一个内存检查器(用于检测内存泄露和其他内存问题)叫做Memcheck,还有一个堆分析器叫做Massif。


甚至有Valgrind的Eclipse集成插件 (http://wiki.eclipse.org/index.php/Linux_Distributions_Project)。 - lothar
不错的提示,我不知道那个项目。通常我使用Cmake,所以通过这个工具和这个链接:http://www.vtk.org/Wiki/Eclipse_CDT4_Generator 我可以将所有的C++开发移植到Linux上的Eclipse CDT中,谢谢。 - javier-sanz
7
使用valgrind massif,有没有一种方法可以对每种对象类型进行剖析并统计对象数量和总内存使用量? - cib

12

对于简单的统计,只需找出内存使用情况,您可以添加类似以下模板:

template<class T>
class Stats {
  static int instance_count;
public:
  Stats() {
    instance_count++;
  }
  ~Stats() {
    instance_count--;
  }
  static void print() {
    std::cout << instance_count << " instances of " << typeid(T).name() <<
        ", " << sizeof(T) << " bytes each." << std::endl;
  }
};

template<class T>
int Stats<T>::instance_count = 0;

然后,您可以将其作为基类添加到您认为具有大量实例的类中,并打印出当前内存使用情况的统计信息:

class A : Stats<A> {
};

void print_stats() {
  Stats<A>::print();
  Stats<B>::print();
  ...
}

这并不会告诉你对象是在哪些函数中分配的,也不会提供太多细节,但它可能足以定位浪费内存的位置。


4
如果你要这样做,请记住这并不是线程安全的。您可能需要使用std::atomic(如果您有C++11)或boost::atomic来进行递增/递减操作。 - Alastair Maw

9

对于Windows系统,请查看“crtdbg.h”中的函数。 crtdbg.h包含内存分配函数的调试版本。它还包含用于检测内存泄漏,损坏,检查堆指针有效性等的函数。

我认为以下函数对您很有用:

_CrtMemDumpStatistics _CrtMemDumpAllObjectsSince

以下MSDN链接列出了堆状态报告函数和示例代码 http://msdn.microsoft.com/en-us/library/wc28wkas(VS.80).aspx


2
那个链接已经失效了,也许是http://msdn.microsoft.com/en-us/library/aa269809(v=vs.60).aspx或者http://msdn.microsoft.com/en-us/library/974tc9t1.aspx? - TankorSmash

6

它支持Linux吗? - Hi-Angel

5

MTuner - 一款免费的 C/C++ 内存分析器。以下是描述:

MTuner 是一个多平台的内存分析、泄漏检测和分析工具,支持 MSVC、GCC 和 Clang 编译器。其特点包括:基于时间线的内存活动历史记录、强大的过滤功能、用于手动插装的 SDK(带有完整源代码)、通过命令行使用的持续集成支持、内存泄漏检测等等。可对任何针对 GCC 或 Clang 交叉编译器的平台进行性能分析。内置支持 Windows、PlayStation 4 和 PlayStation 3 平台以及由基于 Windows 的交叉编译器针对的平台。


1
我如何提交错误报告?我已经尝试了MTuner,但是当启动具有长命令行的可执行文件时它会崩溃。是否有一个Github库? - Amir Gonnen
当尝试加载一个大的 .MTuner 文件(约9GB)时,它也会崩溃。您是否尝试一次性将整个文件加载到内存中?您是否在代码中检查了内存分配失败的情况? - Amir Gonnen
没有Github仓库,这是闭源的。欢迎向我发送更多关于这些崩溃的信息,我会修复它们/查看一下。 - mtosic
我该如何联系你? - Amir Gonnen

3

尝试使用gperftools - 它可以:

  • 一次性对代码的特定部分或整个程序进行分析。
  • 通过可视化有向图表示数据,显示确切的函数调用及其继承关系。
  • 在可视化图中聚焦于特定代码区域。
  • 显示转储之间的差异。
  • 显示分配的空间而不是使用的空间 - 所有这些都可以使用同一个转储文件完成。

此外,它几乎不会影响程序效率。


2
更新:gperftools的新链接现在是:https://github.com/gperftools/gperftools。 - mystery_doctor

3

有几件事情你可以做。最简单的方法是链接一个调试 malloc 库,根据你环境的细节(例如,在 Windows 上搜索 _malloc_dbg),有很多可供选择的库。

第二个选择是在 C++ 中重载 newdelete;你可以重载基本的 new 和 delete 函数,用新函数来跟踪内存分配和使用。


2

我刚刚发布了一个win32本地内存分析器MemPro,作为免费的测试版。 http://www.puredevsoftware.com/MemPro.htm。它钩入new/delete并将数据发送到外部应用程序,在那里您可以以各种不同的方式查看分配情况。希望这对您有所帮助。


1

第4.6章来自《游戏编程宝典8》(Safari图书预览链接),详细介绍了Ricky Lung开发的高级内存分析器,可以以层次化调用堆栈的方式显示分配统计信息,并支持多线程。


1
这个章节不是立即可见的,你有没有真正预览的链接,而不是强制订阅按钮或免费试用? - CoffeDeveloper
链接已损坏。 - Hi-Angel

1
在以前的工作中,我们使用过一种叫做"Purify"的工具。这是由Rational/IBM开发的产品。我认为这不是一种免费的工具,但我记得它非常好用。以下是一些相关信息:

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


2
Purify会告诉您有关内存破坏和泄漏的信息,而不是已分配对象的大小。 - Mathieu JVL

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接