有什么方法可以在 c++ 中找到分配给地图的内存量/大小?有一个函数可以找到映射的大小,即映射中的条目数,但是内存有没有这样的方法。我有一张地图(字符串,字符串)。sizeof() 总是给我 48 的大小。为什么会这样?谢谢 :)
6 回答
没有简单的方法,但如果你真的必须知道(虽然......你为什么会?),那么你可以找到。
默认情况下,所有标准库容器都使用“默认分配器”进行分配,它只不过是一个带有一对包装函数的结构/类,new
并且delete
(在内部,它们本身只不过是包装器,malloc
并free
带有一点对齐和一个在许多编译器上进行类型转换)。
如果您出于某种原因对默认分配器不满意,您可以为容器模板提供自定义分配器,它会无缝地使用该分配器。
如果您编写一个在分配/解除分配时递增/递减整数的分配器,您就会知道动态分配了多少内存。再加上sizeof
超精确的值。
不,那里没有。.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;
}
map 类的大小为 48。map 的实例将在堆栈中创建,我们插入的任何记录都将存储在堆中。所以 map 对象将只是指向堆中的记录。疑惑可能是为什么插入记录后还是48。?由于记录不与地图对象一起存储,因此大小是恒定的 - 48。正如在答案中提到的,对象大小在运行时不会改变。
地图使用的总大小=
((sizeof(key)+sizeof(value))* map.size())+sizeof(map)
map.size() 将给出地图中的记录数
48 是地图实例的大小。
一个对象在运行时不能改变它的大小。对于地图,与大多数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);
由于谷歌把我带到这里,我还是会发布一个迟到的答案——因为接受的答案没有回答这个问题。
这是我所做的(按照 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 不是可重入的。不过,我在多线程单元测试时成功运行了它。
这是一个很好的问题,因为其他答案假设地图元素的大小是固定的。在我的情况下,我有一个结构映射的映射,它的 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);
}