const size_t size = 10000000;
using T = unsigned short[];
vector<unique_ptr<T>> v;
v.resize(size);
for (size_t n = 0; n != size ; ++n) {
v[n] = make_unique<T>(3);
for (int i = 0; i!= 3; ++i)
v[n][i] = rand();
}
我想测量它使用了多少内存。
- 我的期望:10.000.000*(8+2*3) = 140.000.000字节。每个指针8字节,每个unsigned short 2字节。
- What "valgrind -- --tool=memcheck"返回:总堆使用量:10,000,112个分配,10,000,111个释放,140,161,828个字节分配
- 实际情况:Virt = 419044, res = 394180 (kb).
为什么实际尺寸是valgrind显示器的3倍?我在VSL, ubuntu上运行它。
您忘记了内存分配本身的开销。只有new
/delete
本身,必须有东西跟踪它。某个地方。
你很容易,但c++库为你做了所有艰苦的工作。
很简单:你只需要new
一些任意数量的字节,然后delete
它,然后你就完成了。但是对于c++库来说就不那么容易了。它必须知道每个new
ed对象或对象的大小。因此,当它们是delete
d时,c++库知道刚刚删除了多少内存。当内存中相邻的对象获得delete
d时,分配器也需要意识到这一点,并将两个相邻的 CC_7d对象合并到一个更大的内存块中,以便在以后的某个时候可能用于 CC_7d更大的对象。
这种复杂性不是免费的。它需要被跟踪和汇总。
所有这些都至少需要一个指针值,至少需要一个字节计数值。每个分配。一个健壮的内部内存分配器可能想要在某个地方存储一个额外的指针,但是让我们从一个指针和一个字节计数开始,作为内存分配器的一个极简实现。
您一次分配sizeof(unsigned short)*3
字节,或按我的计数分配6字节。在64位平台上,指针需要8字节长。假设您有一个智能内存分配器,它维护一个单独的分配bool,其大小不超过64kb,因此内存字节数只需要2字节。因此,每次分配的开销为10字节。
这个开销需要被存储、跟踪并堆积到每个分配。因此,考虑到每分配6个字节至少要增加10个字节的额外开销,观察到预期的2-3个内存使用量似乎是相当合理的。如果字节计数在内部被跟踪为4字节,或者如果内存池是双链表,需要另一个,则肯定在大致范围内。8个字节(幸运的话可能是4个字节)。
Valgrind只是报告它在拦截对malloc
和new
的调用时看到的内容。
如果你真的想知道有多少内存被使用,试试massif
,也试试--pages-as-heap=yes
的massif。此参数还将导致massif记录使用mmap
映射的页面。