如何分析一组 C++ 类的内存消耗?

Posted

技术标签:

【中文标题】如何分析一组 C++ 类的内存消耗?【英文标题】:How to profile the memory consumption by a set of C++ classes? 【发布时间】:2010-08-27 14:47:36 【问题描述】:

我正在尝试使用 gprof 计算我的 (C++) 程序的内存消耗。该程序没有 gui,它完全基于 cli。

现在,我是 gprof 的新手,所以我阅读了一些教程,它们教会了我如何运行 gprof 并发现时间消耗。

但是,我需要找出一组特定类的内存消耗。 假设有一个程序有多种类型,A, ..., Z。现在我想运行我的程序,看看A, E, I, O, U 类的对象使用了多少累积内存(例如)。

你们有什么想法或指示我可以如何完成这项任务吗? 我不只考虑 gprof,我对任何可以完成工作的 (fos) 软件持开放态度。

当然,我在 google 和 ***.com 上都搜索过这个问题的任何答案,但是要么我使用了错误的关键字,要么没有人遇到这个问题。

编辑:关于手动执行此操作的建议是显而易见的。当然,我可以将它编码到应用程序中,但它涉及大量我不想更改的类。另外,我想知道总内存消耗,所以我不能只计算所有创建的对象,因为我必须单独跟踪对象的大小。

Edit2:我修改了DeadMG's suggestion,我只需要继承它。它工作得很好,所以,如果有人有类似的问题,试试这个。

class GlobalObjectCounter 
  public: 
    struct ClassInfo 
      unsigned long created;
      unsigned long destroyed;
      unsigned short size;
      ClassInfo() : created(0), destroyed(0), size(0) 
      ClassInfo(unsigned short _size) : created(0), destroyed(0), size(_size) 
      void fmt(std::ostream& os) 
        os << "total: " << (this->created) << " obj = " << (this->created*this->size) << "B; ";
        os << "current: " << (this->created-this->destroyed) << " obj = " << ((this->created-this->destroyed) * this->size) << "B; ";
      
    ;
  protected:
    static std::map<std::string,ClassInfo> classes;
    GlobalObjectCounter() 
  public:
    static void dump(std::ostream& os) 
      for (std::map<std::string,ClassInfo>::iterator i = classes.begin(); i != classes.end(); ++i) 
        os << i->first << ": ";
        i->second.fmt(os);
        os << "\n";
      
    
;

template <class T> class ObjectCounter : public GlobalObjectCounter 
  private:
    static ClassInfo& classInfo() 
      static ClassInfo& classInfo = classes[std::string("") + typeid(T).name()];
      classInfo.size = sizeof(T);
      return classInfo;
    
  public:
    ObjectCounter() 
      classInfo().created++;
    
    ObjectCounter(ObjectCounter const& oc) 
      classInfo().created++;
    
    ObjectCounter& operator=(const ObjectCounter&) 
    ~ObjectCounter() 
      classInfo().destroyed++;
    
;

地图查找有点讨厌,我承认,但我没有勇气为每个类存储迭代器。主要问题是您必须为每个计数类显式初始化它。如果您知道如何更好地做到这一点,请告诉我。

【问题讨论】:

【参考方案1】:

我不知道 gprof 甚至试图处理内存使用问题。显而易见的替代方案是valgrind。如果您只关心总内存使用量,您也可以自己完成这项工作(重载 ::operator new::operator delete 以跟踪程序请求了多少内存)。当然,可能您有一些通过其他方式获取内存的代码(例如,直接调用类似sbrk 的东西),但这是相当不寻常的。但是,它们不会尝试跟踪静态分配和/或堆栈使用情况。

【讨论】:

感谢您查看 valgrind 的提示。它似乎比 gprof 更关心内存。【参考方案2】:

微不足道。

template<typename T> class Counter 
    static int count = 0;
    Counter()  count++; 
    Counter(const Counter&)  count++; 
    Counter& operator=(const Counter&) 
    ~Counter()  count--; 
;
class A : Counter<A> 
    static int GetConsumedBytes() 
        return sizeof(A) * count;
    
;

如果 A 的使用涉及动态内存,那么这个解决方案可以改进。您还可以覆盖全局运算符 new/delete。

【讨论】:

只有在没有其他选择的情况下我才会采用这种方法,因为我必须修改源代码。另外我想避免多重继承,因为我们可以有class A: public E。但是感谢您的建议,如果没有其他建议,我可能会在此基础上再接再厉。 静态继承不会被视为与常规继承相同,除此之外,因为没有实际的虚拟方法。 我相信我将不得不接受这样的事情,除非有人有其他想法。但是,我想知道您为什么将GetConsumedBytes 放入A 而不是Counter。这种冗余是目前最让我烦恼的。 A::GetConsumedBytes() 比 Counter::GetConsumedBytes() 短。因为继承是静态的,所以什么都没有关系。 @Puppy 能否请您详细说明动态内存分配很重要时该解决方案的演变?【参考方案3】:

GlibC 提供有关堆内存分配的统计信息。看看mallinfo。您可能会在执行期间的不同点获得统计数据,并了解正在使用的内存量。

【讨论】:

这告诉我总内存,但不能给我更详细的信息,关于各个类。

以上是关于如何分析一组 C++ 类的内存消耗?的主要内容,如果未能解决你的问题,请参考以下文章

控制和分析内存和时间消耗 C++ Windows 应用程序? [关闭]

如何减少python内存的消耗?

Java类的内存性能[关闭]

「C++」频繁分配释放内存导致的性能问题的分析

一文详解C++类的内存布局和虚函数底层实现机制

逆向程序分析:C++的一个空类,为什么在内存中占1字节