我正在填充字符串共享指针的列表。在程序的某个时刻,我清除了列表。但是,即使我调用clear()
list函数,程序的内存消耗也不会减少。知道为什么吗?
#include <memory>
#include <string>
#include <list>
#include <iostream>
int main()
{
std::string text = " \
PREFACE \
\
Most of the adventures recorded in this book really occurred; one or two \
were experiences of my own, the rest those of boys who were schoolmates \
of mine. Huck Finn is drawn from life; Tom Sawyer also, but not from an \
individual--he is a combination of the characteristics of three boys whom \
I knew, and therefore belongs to the composite order of architecture. \
\
The odd superstitions touched upon were all prevalent among children and \
slaves in the West at the period of this story--that is to say, thirty or \
forty years ago. \
\
Although my book is intended mainly for the entertainment of boys and \
girls, I hope it will not be shunned by men and women on that account, \
for part of my plan has been to try to pleasantly remind adults of what \
they once were themselves, and of how they felt and thought and talked, \
and what queer enterprises they sometimes engaged in. \
";
std::list<std::shared_ptr<std::string>> data;
for (auto i = 0u; i < 999999; ++i) {
data.push_back(std::make_shared<std::string>(text));
}
std::cout << "Data loaded. Press any key to continue...";
std::cin.get();
data.clear(); // memory does not reduce
std::cout << "Data unloaded. Press any key to continue...";
std::cin.get();
std::cout << "Container size:" << data.size() << std::endl;
std::cout << "Press any key to exit...";
std::cin.get();
return 0;
}
我正在WSL上调试。我使用了Linux top(在WSL上)和Windows Task Manager来检查每次停止时的内存使用情况。但是valgrind不会报告任何内存泄漏。
PS:请不要问为什么我使用共享指针。提出不同的方法将很有用,但此问题的主要目的是理解这种行为。因为即使cppref也无法解释这一点。欣赏是否有人可以解释这种行为而不是解决它。
我不需要修复。我需要一个解释。
我使用了Linux top(在WSL上)和Windows Task Manager来检查每次停止时的内存使用情况。但是valgrind不会报告任何内存泄漏。
TLDR:相对于其他代码路径,分配内存是一项昂贵的操作。为了提高性能,几乎所有堆管理器都将继续保留内存以进行后续分配,而不是直接将其返回给它。
当您的程序代码分配内存时,它会通过一层内存堆来授予该分配。当您的程序调用“ new”(通过make_shared
)时,它将调用C / C ++运行时来分配内存。C / C ++运行时,如果堆中没有足够大的连续字节范围来分配该分配,它将通过OS特定的库调用将其缩减为进程堆,以请求更多的内存。如果进程堆没有足够的资源立即分配,它会进行系统调用以分配更多的虚拟内存...以及可能还会有更多的堆。而且,别忘了可能必须调入内存,但是我离题了。
这些堆访问中的每一个都需要锁定数据结构以管理请求的堆分配,并且可能需要对OS进行系统调用。可能需要付出额外的努力才能根据需要折叠或重新排列内存块。这就是为什么内存堆是分层的。如果每个新调用和删除调用都直接发送给虚拟内存管理器,则程序和系统的性能将因大量的系统调用而确实变慢。
类似地,将内存释放回原来的位置也会带来类似的性能损失。这些堆可能会在想要压缩时释放回其父堆,但不要指望它会通过单次调用“删除”来做到这一点。
诸如Top和Task Manager之类的工具只能从OS观察进程分配的虚拟内存量。他们不知道程序的运行时库正在管理免费分配。而Valgrind会将自己插入代码中,并且可以将自身挂钩到C ++内存管理器。但是,甚至Valgrind也会不时报告错误肯定。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句