对象消耗了多少内存

How much memory consumed by my object

本文关键字:多少 内存 对象      更新时间:2023-10-16

我想知道编程的方式来获得由我的用户定义类消耗的内存。下面是类

的声明
struct TrieNode {
    typedef std::map<char, TrieNode *> ChildType;
    std::string    m_word;
    bool      m_visited;
}

我将264061周围的单词插入到Trie中。在这之后,当我做sizeof(trieobject)时,它只显示32。我如何知道这些数据结构使用了多少确切的内存

我用

valgrind --tool=massif ./myprogram -opt arg1 arg2
ms_print massif.* | less -SR

。本页

的输出示例
19.63^                                               ###                      
     |                                               #                        
     |                                               #  ::                    
     |                                               #  : :::                 
     |                                      :::::::::#  : :  ::               
     |                                      :        #  : :  : ::             
     |                                      :        #  : :  : : :::          
     |                                      :        #  : :  : : :  ::        
     |                            :::::::::::        #  : :  : : :  : :::     
     |                            :         :        #  : :  : : :  : :  ::   
     |                        :::::         :        #  : :  : : :  : :  : :: 
     |                     @@@:   :         :        #  : :  : : :  : :  : : @
     |                   ::@  :   :         :        #  : :  : : :  : :  : : @
     |                :::: @  :   :         :        #  : :  : : :  : :  : : @
     |              :::  : @  :   :         :        #  : :  : : :  : :  : : @
     |            ::: :  : @  :   :         :        #  : :  : : :  : :  : : @
     |         :::: : :  : @  :   :         :        #  : :  : : :  : :  : : @
     |       :::  : : :  : @  :   :         :        #  : :  : : :  : :  : : @
     |    :::: :  : : :  : @  :   :         :        #  : :  : : :  : :  : : @
     |  :::  : :  : : :  : @  :   :         :        #  : :  : : :  : :  : : @
   0 +----------------------------------------------------------------------->KB     0                                                                   29.48
Number of snapshots: 25
 Detailed snapshots: [9, 14 (peak), 24]

日志的其余部分详细说明了内存分配的最高百分位数,您可以明确地看到哪种类型的类占用了堆内存的百分比(以及从调用堆栈的角度来看,分配来自何处),例如:

--------------------------------------------------------------------------------
  n        time(B)         total(B)   useful-heap(B) extra-heap(B)    stacks(B)
--------------------------------------------------------------------------------
 10         10,080           10,080           10,000            80            0
 11         12,088           12,088           12,000            88            0
 12         16,096           16,096           16,000            96            0
 13         20,104           20,104           20,000           104            0
 14         20,104           20,104           20,000           104            0
99.48% (20,000B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
->49.74% (10,000B) 0x804841A: main (example.c:20)
| 
->39.79% (8,000B) 0x80483C2: g (example.c:5)
| ->19.90% (4,000B) 0x80483E2: f (example.c:11)
| | ->19.90% (4,000B) 0x8048431: main (example.c:23)
| |   
| ->19.90% (4,000B) 0x8048436: main (example.c:25)
|   
->09.95% (2,000B) 0x80483DA: f (example.c:10)
  ->09.95% (2,000B) 0x8048431: main (example.c:23)

嗯,这不是那么容易做到的。首先m_word是一个可变大小的字符串,对吧?在std::string内部保存了一个字符数组。std::map也是如此。我猜你可以根据地图* TrieNode的大小得到一个粗略的估计,但这只是一个粗略的估计。

我认为使用外部工具进行代码分析会更有帮助。如果你没有任何工具,你甚至可以使用任务管理器:)。

您的"对象大小"是sizeof(std::string) + sizeof(bool) + m_word.capacity() +填充字节或sizeof(trieobject) + m_word.capacity()

这是我想出的一段GCC代码,您可以在测试程序中使用它,其中您只实例化类的一个对象并使用它进行一些典型的工作。代码替换了全局operator new()operator delete();因此,它将只通过::new表达式和标准分配器跟踪分配,前提是标准分配器本身使用::operator new()(这是GCC的情况)。

由于需要跟踪指针及其分配,因此需要单独的map,当然不能使用标准分配器本身;GCC的malloc-allocator来帮忙了。

我们使用一个静态初始化的全局变量使内存跟踪器在main返回后打印它的数据。

#include <unordered_map>
#include <string>
#include <iostream>
#include <ext/malloc_allocator.h>
struct Memtrack
{
  typedef std::unordered_map<void*, std::size_t, std::hash<void*>,
     std::equal_to<void*>, __gnu_cxx::malloc_allocator<void*>> AllocMap;
  static int memtrack;
  static int memmax;
  static AllocMap allocs;
  Memtrack() { std::cout << "starting tracker: cur = " << memtrack  << ", max = " << memmax << ".n"; }
  ~Memtrack() { std::cout << "ending tracker: cur = " << memtrack  << ", max = " << memmax << ".n"; }
  static void track_new(std::size_t n, void * p)
  {
    memtrack += n;
    if (memmax < memtrack) memmax = memtrack;
    allocs[p] = n;
    std::cout << "... allocating " << n << " bytes...n";
  }
  static void track_delete(void * p)
  {
    const int n = int(allocs[p]);
    memtrack -= n;
    std::cout << "... freeing " << n << " bytes...n";
  }
} m;
int Memtrack::memtrack = 0;
int Memtrack::memmax = 0;
Memtrack::AllocMap Memtrack::allocs;
void * operator new(std::size_t n) throw(std::bad_alloc)
{
  void * const p = std::malloc(n);
  Memtrack::track_new(n, p);
  return p;
}
void operator delete(void * p) throw()
{
  Memtrack::track_delete(p);
  std::free(p);
}
int main()
{
  std::cout << "Beginning of main.n";
  std::unordered_map<std::string, int> m;  // this piece of code
  m["hello"] = 4;                          // is a typical test for working
  m["world"] = 7;                          // with dynamic allocations
  std::cout << "End of main.n";
}

典型输出:

starting tracker: cur = 0, max = 0.
Beginning of main.
... allocating 48 bytes...
... allocating 12 bytes...
... allocating 12 bytes...
End of main.
... freeing 12 bytes...
... freeing 12 bytes...
... freeing 48 bytes...
ending tracker: cur = 0, max = 72.

不重要。如果您有一些时间(如果您只对调试/优化目的的大小感兴趣,则可能是这种情况)。这种方法可能不适合生产代码!

#include <malloc.h>
template <typename T> int objSize(T const* obj) {
  // instead of uordblks, you may be interested in 'arena', you decide!
  int oldSize = mallinfo().uordblks;
  T* dummy = new T(*obj);
  int newSize = mallinfo().uordblks;
  delete dummy;
  return newSize - oldSize;
}