Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Account memory usage with custom allocator

I'm using a custom allocator to account for memory usage in several containers. Currently I use a static variable to account for the memory usage. How could I separate this account across several containers without having to rewrite the allocator to use different static variables?


static size_t allocated = 0;


   template <class T>
   class accounting_allocator {
     public:
       // type definitions
       typedef T        value_type;
       typedef T*       pointer;
       typedef const T* const_pointer;
       typedef T&       reference;
       typedef const T& const_reference;
       typedef std::size_t    size_type;
       typedef std::ptrdiff_t difference_type;
       //static size_t allocated;

       // rebind allocator to type U
       template <class U>
       struct rebind {
           typedef accounting_allocator<U> other;
       };

       // return address of values
       pointer address (reference value) const {
           return &value;
       }
       const_pointer address (const_reference value) const {
           return &value;
       }

       /* constructors and destructor
        * - nothing to do because the allocator has no state
        */
       accounting_allocator() throw() {
       }
       accounting_allocator(const accounting_allocator&) throw() {
       }
       template <class U>
         accounting_allocator (const accounting_allocator<U>&) throw() {
       }
       ~accounting_allocator() throw() {
       }

       // return maximum number of elements that can be allocated
       size_type max_size () const throw() {
        //  std::cout << "max_size()" << std::endl;
           return std::numeric_limits<std::size_t>::max() / sizeof(T);
       }

       // allocate but don't initialize num elements of type T
       pointer allocate (size_type num, const void* = 0) {
           // print message and allocate memory with global new
           //std::cerr << "allocate " << num << " element(s)" << " of size " << sizeof(T) << std::endl;
           pointer ret = (pointer)(::operator new(num*sizeof(T)));
           //std::cerr << " allocated at: " << (void*)ret << std::endl;
           allocated += num * sizeof(T);
            //std::cerr << "allocated: " << allocated/(1024*1024) << " MB" << endl;
           return ret;
       }

       // initialize elements of allocated storage p with value value
       void construct (pointer p, const T& value) {
           // initialize memory with placement new
           new((void*)p)T(value);
      }

       // destroy elements of initialized storage p
       void destroy (pointer p) {
           // destroy objects by calling their destructor
           p->~T();
       }

       // deallocate storage p of deleted elements
       void deallocate (pointer p, size_type num) {
           // print message and deallocate memory with global delete
#if 0
           std::cerr << "deallocate " << num << " element(s)"
                     << " of size " << sizeof(T)
                     << " at: " << (void*)p << std::endl;
#endif
           ::operator delete((void*)p);
           allocated -= num * sizeof(T);
       }
   };
  template<>
    class accounting_allocator<void>
    {
    public:
      typedef size_t      size_type;
      typedef ptrdiff_t   difference_type;
      typedef void*       pointer;
      typedef const void* const_pointer;
      typedef void        value_type;

      template<typename _Tp1>
        struct rebind
        { typedef allocator<_Tp1> other; };
    };


   // return that all specializations of this allocator are interchangeable
   template <class T1, class T2>
   bool operator== (const accounting_allocator<T1>&,
                    const accounting_allocator<T2>&) throw() {
       return true;
   }
   template <class T1, class T2>
   bool operator!= (const accounting_allocator<T1>&,
                    const accounting_allocator<T2>&) throw() {
       return false;
   }
like image 891
piotr Avatar asked Oct 27 '09 09:10

piotr


People also ask

What is custom allocator?

Allocators handle all the requests for allocation and deallocation of memory for a given container. The C++ Standard Library provides general-purpose allocators that are used by default, however, custom allocators may also be supplied by the programmer.

Does std :: allocator use malloc?

Under the hood, the C function std::malloc will typically be used. Therefore, an allocator, who uses preallocated memory can gain a great performance boost. An adjusted allocator also makes a lot of sense, if you need a deterministic timing behavior of your program.

What does allocator mean in C++?

std::allocator is used when you want to separate allocation and do construction in two steps. It is also used when separate destruction and deallocation is done in two steps. All the STL containers in C++ have a type parameter Allocator that is by default std::allocator.

How does an allocator work?

A Merchandise Allocator allocates merchandise to stores according to warehouse and store inventory levels. Will assist stores with merchandise transfers to fulfill stock needs. Being a Merchandise Allocator may require a bachelor's degree. Typically reports to a supervisor or manager.


1 Answers

If you mean that you want a separate counter for each container type, you could simply include the container type as a template parameter and uncomment static size_t allocated so it's a static member variable. This way, a separate counter variable will be generated for each type of container.

If you're saying you want a separate counter for each instance of a container, you need to make size_t allocated a non-static member variable. The problem is, you'll also need some kind of hook so you can access the allocation counter from outside each container. The STL allocator design makes it difficult to do this. Some STL containers have a constructor that lets you pass an instance of an allocator, but not all containers support this. On containers that support this, you can include a reference to some global map inside your allocator class, and then pass an instance of your allocator to the constructor of each container. Then, when you call accounting_allocator::allocate(), the allocator would record the number of bytes it has allocated in the global map. Still, I can't see how you could easily associate this information with a particular container instance, since the allocator object does not know which container it belongs to.

Honestly, if you're just collecting debug info, it's probably easier to just define a non static size_t allocated, and have accounting_allocator::allocate() simply output the stats to a file or to stdout. Alternatively, look into using a memory profiler tool for the platform you develop on.

like image 57
Charles Salvia Avatar answered Sep 25 '22 10:09

Charles Salvia