Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I know how much memory an STL object takes?

Tags:

c++

memory

stl

I need to gather statistics about memory usage in my program.

My code is mostly written using STL.

Is there any way of learning how much memory is being consumed by an STL object?

For example,

string s1 = "hello";
string s2 = "hellohellohellohellohellohellohellohellohellohellohellohellohello";

How much memory is consumed by s1 and s2? Obviously, sizeof(string)+s1.length() is not quite accurate.

like image 834
limi Avatar asked Sep 16 '11 17:09

limi


People also ask

How much memory does a std vector use?

So there is no surprise regarding std::vector. It uses 4 bytes to store each 4 byte elements.

Does vector use more memory?

These abilities come at a price: vectors consume more memory in exchange to handle storage and grow dynamically in size.

Are STL containers slow?

Yes, you are correct. Using the vector or string like that is indeed slow. Basically every time you append you're appending to the end of the container, you're potentially asking the container to reallocate a new buffer, copy the data over to the new buffer, and delete the old buffer.


2 Answers

Since this is completely implementation details, you cannot determine this with 100% accuracy.

However, as you said, you want to put some code to statistics the memory usage in your program, then you can do that with some accuracy.

I believe, for std::string, the size of memory taken by string objects, will be almost equal to:

size_t statisticalSizeStr = sizeof(string)+ s.capacity() * sizeof(char);

And similarly, for std::vector

size_t statisticalSizeVec = sizeof(std::vector<T>)+ ....;

You can model your statistical estimation on such informations. For vector, you can also consider the size of T in the same way which will fill the .... in the above equation. For example, if T is std::string, then:

size_t vecSize = sizeof(std::vector<std::string>);
size_t statisticalSizeVec = vecSize  + v.capacity() * statisticalSizeStr;

And if T is int, then

size_t statisticalSizeVec=sizeof(std::vector<int>)+v.capacity()*sizeof(int);

I hope, such analysis would help you to compute the size with as much accuracy as possible.

like image 32
Nawaz Avatar answered Oct 16 '22 14:10

Nawaz


If you're willing to be slightly intrusive, you can make a custom allocator to track all heap usage by container type, or by type allocated. This is quite intrusive, but quite accurate as well, for determining memory usage. This does not track how much memory the heap itself takes though, as that is highly OS-dependent.

template<class TrackType> 
size_t* mem_used() {static size_t s = 0; return &s;}

template<class T, class TrackType, class BaseAllocator = std::allocator<T> > 
class TrackerAllocator : public BaseAllocator {
public:
    typedef typename BaseAllocator::pointer pointer;
    typedef typename BaseAllocator::size_type size_type;

    TrackerAllocator() throw() : BaseAllocator() {}
    TrackerAllocator(const TrackerAllocator& b) throw() : BaseAllocator(b) {}
    TrackerAllocator(TrackerAllocator&& b) throw() : BaseAllocator(b) {}
    template <class U> TrackerAllocator(const typename TrackerAllocator::template rebind<U>::other& b) throw() : BaseAllocator(b) {}
    ~TrackerAllocator() {}

    template<class U> struct rebind {
        typedef TrackerAllocator<U, TrackType, typename BaseAllocator::template rebind<U>::other> other;
    };

    pointer allocate(size_type n) {
        pointer r = BaseAllocator::allocate(n);
        *mem_used<TrackType>() += n;
        return r;
    }
    pointer allocate(size_type n, pointer h) {
        pointer r = BaseAllocator::allocate(n, h);
        *mem_used<TrackType>() += n;
        return r;
    }
    void deallocate(pointer p, size_type n) throw() {
        BaseAllocator::deallocate(p, n);
        *mem_used<TrackType>() -= n;
    }
};

And usage is:

typedef std::basic_string<char, 
                          std::char_traits<char>,
                          TrackerAllocator<char, std::string> > trackstring;
typedef std::vector<int, 
                    TrackerAllocator<int, std::vector<int> > > trackvector;
//                                        ^              ^
//                                        This identifies which memory to track
//                                        it can be any type, related or no.
//                                        All with the same type will be tracked togeather
int main() {
    trackstring mystring1("HELLO WORLD");
    std::cout << *mem_used<std::string>() << '\n'; //display memory usage of all strings

    trackstring mystring2("MUCH LONGER STRING THAT DEFINITELY GETS HEAP ALLOCATED!");
    std::cout << *mem_used<std::string>() << '\n'; //display memory usage of all strings

    trackvector myvec(mystring1.begin(), mystring1.end());
    std::cout << *mem_used<std::vector<int> >() << '\n'; //display memory usage of all vector<int>
    //                     ^              ^
    //                     This identifies which memory type from above to look up.
    return 0;
}

Windows results:

0 //this is zero, because the string did not allocate heap space.
64
11

http://ideone.com/lr4I8 (GCC) results:

24
92
11

like image 102
Mooing Duck Avatar answered Oct 16 '22 14:10

Mooing Duck