8

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

4

6 回答 6

5

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

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

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

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

于 2012-07-18T09:26:36.423 回答
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;
}
于 2012-07-18T08:26:26.193 回答
1

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

地图使用的总大小=

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

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

48 是地图实例的大小。

于 2015-08-13T09:33:52.570 回答
0

一个对象在运行时不能改变它的大小。对于地图,与大多数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);
于 2012-07-18T08:25:04.677 回答
0

由于谷歌把我带到这里,我还是会发布一个迟到的答案——因为接受的答案没有回答这个问题。

这是我所做的(按照 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 不是可重入的。不过,我在多线程单元测试时成功运行了它。

于 2018-09-27T19:14:23.723 回答
0

这是一个很好的问题,因为其他答案假设地图元素的大小是固定的。在我的情况下,我有一个结构映射的映射,它的 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);
}
于 2021-11-16T02:52:11.320 回答