c++memoryboost-bimap

How to find the memory take by boost bimap


I have a boost bimap

#include <iostream>
#include <utility>
#include <boost/bimap.hpp>
#include <boost/bimap/set_of.hpp>
#include <boost/bimap/multiset_of.hpp>

namespace bimaps = boost::bimaps;
typedef boost::bimap<bimaps::set_of<unsigned long long int>,
        bimaps::multiset_of<unsigned long long int > > bimap_reference;
typedef bimap_reference::value_type position;
bimap_reference numbers;

int main()
{
    numbers.insert(position(12345689, 1000000000));
    numbers.insert(position(23456789, 8000000000));   
    return 0;
}

I have about 180000000 entries. Theoretically it should take ~2.7GB of space (180000000*8*2 = 2880000000 bytes = 2880000000/ 1024*1024*1024 = ~2.7GB ). Now I want to find the actual space taken by boost bimap, how can I do that.


Solution

  • Like the comments under your question mention, you can overload the new and delete operators to track memory allocations and deallocations. The example under the Global replacements section of this article shows a very simple example:

    void* operator new(std::size_t sz) {
        std::printf("global op new called, size = %zu\n", sz);
        return std::malloc(sz);
    }
    void operator delete(void* ptr) noexcept {
        std::puts("global op delete called");
        std::free(ptr);
    }
    

    The only problem with this example that you cannot determine how much memory is freed. To solve this issue, check out the accepted answer of How to track memory allocations in C++ (especially new/delete) question.

    The example inside the mentioned answer uses std::map with custom allocator to store the addresses and sizes of allocated memory blocks. Inside the delete operator overload it removes elements with specified addresses. With almost no modifications it can be used to your requirements:

    #include <map>
    
    template<typename T>
    struct MemoryMapAllocator : std::allocator<T> {
        typedef typename std::allocator<T>::pointer pointer;
        typedef typename std::allocator<T>::size_type size_type;
        template<typename U> struct rebind { typedef MemoryMapAllocator<U> other; };
    
        MemoryMapAllocator() {}
    
        template<typename U>
        MemoryMapAllocator(const MemoryMapAllocator<U>& u) : std::allocator<T>(u) {}
    
        pointer allocate(size_type size, std::allocator<void>::const_pointer = 0) {
            void* p = std::malloc(size * sizeof(T));
            if(p == 0)
                throw std::bad_alloc();
            return static_cast<pointer>(p);
        }
        void deallocate(pointer p, size_type) {
            std::free(p);
        }
    };
    
    typedef std::map<void*, std::size_t, std::less<void*>,
                MemoryMapAllocator<std::pair<void* const, std::size_t>>> MemoryMap;
    
    MemoryMap& getMemoryMap() {
        static MemoryMap memMap;
        return memMap;
    }
    
    std::size_t totalAllocatedMemory() {
        std::size_t sum = 0;
        for(auto& e : getMemoryMap())
            sum += e.second;
        return sum;
    }
    
    void* operator new(std::size_t size) {
        void* mem = std::malloc(size == 0 ? 1 : size);
    
        if(mem == 0)
            throw std::bad_alloc();
    
        getMemoryMap()[mem] = size;
        return mem;
    }
    
    void operator delete(void* mem) {
        getMemoryMap().erase(mem);
        std::free(mem);
    }
    

    Live Demo