Как профилировать потребление памяти набором классов C ++? - PullRequest
2 голосов
/ 27 августа 2010

Я пытаюсь выяснить потребление памяти моей (C ++) программой с использованием gprof. Программа не имеет графического интерфейса, она полностью основана на cli.

Теперь я новичок в gprof, поэтому я прочитал несколько уроков, которые научили меня запускать gprof и определять время потребление.

Однако мне нужно выяснить потребление памяти конкретным набором классов. Скажем, есть программа со многими типами, A, ..., Z. Теперь я хочу запустить свою программу и посмотреть, сколько накопленной памяти было использовано объектами классов A, E, I, O, U (например).

Ребята, есть ли у вас какие-либо идеи или указания, как я могу решить эту задачу?
Я не только рассматриваю gprof, я открыт для любого (fos) программного обеспечения, которое выполняет свою работу.

Я, конечно, искал и google, и stackoverflow.com, чтобы найти какой-либо ответ на эту проблему, но либо я использую неправильные ключевые слова, либо ни у кого нет этой проблемы.

Редактировать: Предложения по выполнению этого вручную очевидны. Конечно, я мог бы закодировать его в приложении, но о множестве классов я бы предпочел не менять. Кроме того, я хочу иметь общее потребление памяти, поэтому я не могу только сосчитать все созданные объекты, потому что мне придется отслеживать размер объекта по отдельности.

Edit2: я пошел с модификацией предложения DeadMG , от которого мне нужно только унаследовать. Это работает довольно хорошо, поэтому, если у кого-то есть схожие проблемы, попробуйте это.

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++;
    }
};

Поиск на карте немного неприятен, я признаю это, но у меня не хватило смелости позаботиться о сохранении итератора для каждого класса. Основная проблема заключалась в том, что вам пришлось бы явно инициализировать его для каждого подсчитанного класса. Если вы знаете, как это сделать лучше, скажите мне, как.

Ответы [ 3 ]

4 голосов
/ 27 августа 2010

Я не знаю, gprof даже пытался решать вопросы использования памяти. Очевидная альтернатива будет valgrind. Если вас беспокоит только общее использование памяти, вы также можете выполнить эту работу самостоятельно (перегрузите ::operator new и ::operator delete, чтобы отследить, сколько памяти запрошено программой). Конечно, возможно , что у вас есть код, который получает память другими способами (например, напрямую вызывая что-то вроде sbrk), но это довольно необычно. Тем не менее, они не пытаются отслеживать статически распределенное и / или использование стека.

3 голосов
/ 27 августа 2010

Trivial.

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.

1 голос
/ 27 августа 2010

GlibC предоставляет статистику по выделению памяти в куче. Взгляните на mallinfo . Вы могли бы, вероятно, получить статистику в различных точках во время выполнения и получить некоторое представление о том, сколько памяти используется.

...