【问题标题】:Any way to find size of memory allocated to map?有什么方法可以找到分配给映射的内存大小?
【发布时间】:2012-07-18 08:20:30
【问题描述】:

有没有什么方法可以在 c++ 中找到分配给映射的内存量/大小? 有一个函数可以找到映射的大小,即映射中的条目数,但是内存有没有这样的方法。 我有一张地图(字符串,字符串)。 sizeof() 总是给我 48 的大小。为什么会这样? 谢谢:)

【问题讨论】:

    标签: c++ dictionary


    【解决方案1】:

    没有简单的方法,但如果你真的必须知道(虽然......你为什么会知道?),那么你可以找出来。

    默认情况下,所有标准库容器都使用“默认分配器”进行分配,它只不过是一个结构/类,带有一对围绕 newdelete 的包装函数(它们本身在内部仅比mallocfree 的包装器,在许多编译器上进行了一些对齐和类型转换。

    如果您出于某种原因对默认分配器不满意,您可以为容器模板提供自定义分配器,它会无缝地使用该分配器。

    如果您编写了一个在分配/解除分配时递增/递减整数的分配器,您就知道动态分配了多少内存。再加上sizeof 的值,非常精确。

    【讨论】:

      【解决方案2】:

      一个对象在运行时不能改变它的大小。对于地图,与大多数std 容器一样,内存是在后台动态分配的。要找到地图占用和管理的总大小,您可以执行以下操作:

      std::map<X,Y> mymap;
      int totalSize = sizeof(mymap);
      int noElements = 0;
      
      for ( std::map<X,Y>::iterator i = mymap.begin() ; i != mymap.end() ; i++ )
         noElements++;
      
      totalSize += noElements * sizeof(X);
      totalSize += noElements * sizeof(Y);
      

      【讨论】:

      • 并且还有一个指向地图对象的指针,该指针在空间方面可以忽略不计(编辑:对于地图来说不是那么可以忽略不计)。但是如果你有 100 万个对象,你可能会使用(编辑:超过)4bytes*1000000 = Near(编辑:超过)4 MB 的空间用于指针
      • 这不包括管理数据结构的内部指针。如果这是你需要的,那你很好。另外,当您可以使用map::size 时,为什么还要手动计数?
      • @tuğrulbüyükışık:我不会说微不足道。在std::map&lt;int, int&gt; 中,由于指针导致的空间消耗可能是int 本身的3 倍......
      • @pmr: map::size 给出映射中的条目数。我想要的是分配的内存量。
      【解决方案3】:

      map 类的大小为 48。map 的实例将在堆栈中创建,我们插入的任何记录都将存储在堆中。所以 map 对象将只是指向堆中的记录。疑惑可能是为什么插入记录后还是48。?由于记录不与地图对象一起存储,因此大小是恒定的 - 48。正如答案中提到的,对象大小在运行时不会改变。

      地图使用的总大小=

      ((sizeof(key)+sizeof(value))* map.size())+sizeof(map)
      

      map.size() 将给出地图中的记录数

      48 是地图实例的大小。

      【讨论】:

      • 树结构是动态分配的。这不会计算红黑树。
      【解决方案4】:

      不,没有。但是,对于支持 .size 方法的类(例如字符串或标准容器),您可以实现类似的功能:

      template <class Key, class Value>
      unsigned long mapSize(const std::map<Key,Value> &map){
          unsigned long size = sizeof(map);
          for(typename std::map<Key,Value>::const_iterator it = map.begin(); it != map.end(); ++it){
              size += it->first.size();
              size += it->second.size();
          }
          return size;
      }
      

      如果你想知道分配的内存,你可以使用.capacity

      template <class Key, class Value>
      unsigned long mapCapacity(const std::map<Key,Value> &map){
          unsigned long cap = sizeof(map);
          for(typename std::map<Key,Value>::const_iterator it = map.begin(); it != map.end(); ++it){
              cap += it->first.capacity();
              cap += it->second.capacity();
          }
          return cap;
      }
      

      【讨论】:

      • @user1291063:不客气。请注意,这仍然会比实际使用的内存少一点,因为它不计算指针的内存,所以它仍然只是一个估计值。但是,您可以按照 Damon 的建议使用自定义分配器,这将使您能够跟踪所有内存。
      • 这不计算树本身的大小,只计算内容。
      【解决方案5】:

      既然谷歌把我带到这里,我还是会发布一个迟到的答案——因为接受的答案不能回答问题。

      这是我所做的(按照 Damon 的建议),这取决于 malloc 的实现。在 glibc/linux 上,返回指针后面的位置给出了分配的大小,因此,可以使用以下代码来跟踪分配/释放的字节:

      #define HEAP_TRACE
      
      #include <new>
      
      static size_t                             heap_trace_allocated_bytes            = 0;
      static size_t                             heap_trace_deallocated_bytes          = 0;
      static size_t                             heap_trace_allocated_bytes_baseline   = 0;
      static size_t                             heap_trace_deallocated_bytes_baseline = 0;
      
      void* operator new(std::size_t size) {
          void* alloc_entry = std::malloc(size);
          if (!alloc_entry) {
              throw std::bad_alloc();
          }
          heap_trace_allocated_bytes += *(size_t*)(((size_t)alloc_entry)-sizeof(size_t));
          //std::cout << "(-1) equals " << size << " : " << *(size_t*)(((size_t)alloc_entry)-sizeof(size_t)) << std::endl << std::flush;
          return alloc_entry;
      }
      
      void operator delete(void* alloc_entry) noexcept {
          heap_trace_deallocated_bytes += *(size_t*)(((size_t)alloc_entry)-sizeof(size_t));
          //std::cout << "(-1) : " << *(size_t*)(((size_t)alloc_entry)-sizeof(size_t)) << std::endl << std::flush;
          std::free(alloc_entry);
      }
      
      void setHeapTraceBaseline() {
          heap_trace_allocated_bytes_baseline   = heap_trace_allocated_bytes;
          heap_trace_deallocated_bytes_baseline = heap_trace_deallocated_bytes;
      }
      
      void getHeapTraceInfo(string title) {
          std::cout << "\t" << title << ":" << std::endl;
          std::cout << "\t\tAllocations:   " << (heap_trace_allocated_bytes   - heap_trace_allocated_bytes_baseline)   << " bytes" << std::endl;
          std::cout << "\t\tDeallocations: " << (heap_trace_deallocated_bytes - heap_trace_deallocated_bytes_baseline) << " bytes" << std::endl;
          std::cout << std::endl << std::flush;
      }
      

      用法如下:

      setHeapTraceBaseline();
      // your algorithms
      getHeapTraceInfo("My Algorithm allocation costs");
      

      希望这对某人有所帮助。

      注意:这并不意味着在生产中使用,因为我的 new 不是可重入的。不过,我在多线程单元测试时成功运行了它。

      【讨论】:

        【解决方案6】:

        这是一个很好的问题,因为其他答案假定地图元素的大小是固定的。就我而言,我有一个结构映射的映射,它的 size() 无助于评估。

        我通过挂钩 malloc 函数解决了这个问题,然后使用模板函数创建感兴趣对象的直接副本,该模板函数将自动执行每个子对象的分配,给出容器的总大小及其内容。

        #include <malloc.h>
        
        size_t bucket = 0;
        
        static void* plumber_hook(size_t size, const void* caller);
        static void* plumber_hook(size_t size, const void* caller)
        {
            void*   result;
        
            /* Restore all old hooks */
            /* Call recursively */
            __malloc_hook       = 0;
            {
                result = malloc(size);
            }
            __malloc_hook       = plumber_hook;
        
            bucket += size;
        
            return result;
        }
        
        
        template<typename T>
        size_t plumberTest(T& t)
        {
            //begin plumbing
            bucket = 0;
            
            __malloc_hook   = plumber_hook;
            {
                T newT = t;
            }
            __malloc_hook   = 0;
        
            return bucket;
        }
        
        void plumber()
        {
            size_t gross_size = plumberTest(someMap);   
            printf("someMap and its contents uses at least %ld bytes of space\n", gross_size);
        }
        

        【讨论】:

          猜你喜欢
          • 2023-03-03
          • 2011-01-23
          • 1970-01-01
          • 1970-01-01
          • 2020-10-01
          • 1970-01-01
          • 2019-11-21
          • 1970-01-01
          • 2017-10-26
          相关资源
          最近更新 更多