如果我像这样声明一个 HashMap :
std::unordered_map <int, int> m;
在我放入任何内容之前,实际为 map 分配了多少内存?
最佳答案
它是实现定义的,但您可以通过 sizeof
的组合来观察您正在使用的任何给定实现的内存使用情况(对于 unordered_map
对象本身),以及记录动态分配请求的自定义分配器策略。
我在 godbolt 上编码了它 - https://godbolt.org/z/eoGfvv4zf - 只需编写一个最小的自定义分配器,以使其在最新版本的 gcc、clang 和 msvc 下运行。下面的代码也可供引用。
截至2022年12月29日,显示sizeof
64 对于 gcc 12 和 clang 15,它们在插入完成之前不会向分配器请求额外的内存,而 msvc v19 有 sizeof 40
并且即使在空的情况下也会要求分配器提供额外的内存,并分配 80 字节(加上内存分配库可能具有的任何管理开销):
allocate(1 struct std::_List_node<struct std::pair<int const ,int>,void *> == 16 bytes)
allocate(16 class std::_List_unchecked_iterator<class std::_List_val<struct std::_List_simple_types<struct std::pair<int const ,int> > > > == 64 bytes)
#include <unordered_map>
#include <iostream>
#include <utility>
template <typename T>
struct my_allocator {
my_allocator() = default;
template< class U >
constexpr my_allocator( const my_allocator<U>& other ) noexcept { }
using Base = std::allocator<T>;
Base base;
using value_type = typename Base::value_type;
T* allocate(std::size_t n, const void* hint) {
return allocate(n);
}
[[nodiscard]] constexpr T* allocate(std::size_t n) {
std::cout << "allocate(" << n << ' ' << typeid(T).name()
<< " == " << n * sizeof(T) << " bytes)\n";
return base.allocate(n);
}
constexpr void deallocate(T* p, std::size_t n) {
base.deallocate(p, n);
}
};
int main() {
std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, my_allocator<std::pair<const int, int>>> m;
std::cout << "sizeof " << sizeof m << '\n';
for (int i = 0; i < 1; ++i)
m[i] = i;
std::cout << "buckets: " << m.bucket_count() << '\n';
}
关于c++ - 初始空的 unordered_map 使用多少内存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74646523/