Reputation: 135
Is there any method to find the amount/size of memory allocated to a map in c++? There is a function to find the size of the map,ie,number of entries in the map, but is there any such method for the memory. I have a map ( string, string). The sizeof() is always giving me a size of 48. Any reason why this is so? Thanks :)
Upvotes: 11
Views: 19231
Reputation: 49
This is a good question because other answers assume a fixed size of map elements. In my case I have a map of maps of maps of structs, which size() does not help to evaluate.
I solved this problem by hooking into the malloc function, and then creating a direct copy of the object of interest using a template function, which will automatically perform allocations of each sub-object, giving the gross size of the container and its contents.
#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);
}
Upvotes: 0
Reputation: 705
Since google lead me here, I'll post a little late answer anyway -- since the accepted answer does not answer the question.
Here is what I did (along the lines suggested by Damon), which depends on the malloc implementation. On glibc/linux, the position just behind the returned pointer gives the size of the allocation, therefore, one can use the following code to track bytes allocated/deallocated:
#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;
}
and the usage goes as follows:
setHeapTraceBaseline();
// your algorithms
getHeapTraceInfo("My Algorithm allocation costs");
Hope this helps someone.
Note: That was not meant for use in production, since my new is not reentrant. I ran it successfully while multithread unit testing, though.
Upvotes: 0
Reputation: 177
The size of the map class is 48. The instance for the map will be created in the stack and whatever records we insert will be stored in the heap. So map object will be just pointing to the records in the heap. The doubt may be like why it is 48 even after inserting records.? As the records are not stored along with map object the size is constant - 48. As mentioned here in the answers object size won't change in the run time.
Total Size used by map=
((sizeof(key)+sizeof(value))* map.size())+sizeof(map)
map.size() will give the number of records in the map
48 is size of the map instance.
Upvotes: 1
Reputation: 105886
No, there is not. However you can achieve something similar for classes that support a .size
method such as strings or standard container:
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;
}
If you want to know the allocated memory you could use .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;
}
Upvotes: 5
Reputation: 70136
There is no easy way, but if you really must know (though... why would you?), then you can find out.
All standard library containers by default allocate using a "default allocator" which is not much more than a struct/class with a pair of wrapper functions around new
and delete
(which themselves are, internally, little more than wrappers around malloc
and free
with a little alignment and a type cast on many compilers).
If you are not happy with the default allocator for whatever reason, you can provide a custom allocator to the container template, and it will just seamlessly use that one.
If you write an allocator that increments/decrements an integer at allocation/deallocation, you know how much memory has been dynamically allocated. Add to that the value of sizeof
to be super precise.
Upvotes: 4
Reputation: 258618
An object can't change its size during run-time. For a map, as most std
containers, memory is allocated dynamically under the hood. To find the total size the map occupies and manages you can do:
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);
Upvotes: 0