为什么 std::queue 在弹出元素后不缩小内存?
Why doesn't std::queue shrink its memory after popping elements?
我写了一个小程序,使用std::queue
queue<double> the_queue;
for(int i = 0; i < 100; i++)
{
for(int j = 0; j < 5000; j++)
{
double d = 1.0 * (rand() % 1000);
the_queue.push(d);
}
}
printf("Done pushingn");
while(!the_queue.empty())
{
the_queue.pop();
}
printf("Done poppingn");
我在printf("Done pushingn");
和printf("Done poppingn");
设置了2个断点,并在遇到断点时检查程序的内存使用情况(在任务管理器中显示)。在Done pushing
时,内存占用率为~ 34 mb,而在Done popping
时,内存占用率仍为~ 34 mb。真让我吃惊!
为什么会这样?有办法克服这个吗?
基本上std::queue
是一个适配器容器 -它本身不是一个容器,而是对其他容器的薄包装。
例如,让我们看看队列签名:
template <class T, class Container = deque<T> > class queue;
可以看到,T
是存储在队列中的元素的类型,Container
是底层容器。
,这就是你问题的答案:不同的容器处理内存的方式不同。底层的deque可以收缩,也可以不收缩,但这取决于内部的deque。
也可以使用std::list
作为底层容器。在这种情况下,每个pop删除底层列表节点内存。
还可以编写自己的或修改现有的容器以匹配自己的内存管理模式。您的容器需要支持一些方法(如push_back
, pop_front
),您可以在相关的在线文档中阅读。
下面是一个deque
适配器的例子,它每1024次pop
调用就会缩小容量:
template<class T>
class DequeAdapter{
private:
std::deque<T> m_Deque;
size_t m_PopCount;
public:
DequeAdapter():
m_PopCount(0){}
bool empty() const noexcept{
return m_Deque.empty();
}
size_t size() const noexcept{
return m_Deque.size();
}
T& front() noexcept{
return m_Deque.front();
}
const T& front()const noexcept{
return m_Deque.front();
}
T& back() noexcept{
return m_Deque.back();
}
const T& back()const noexcept{
return m_Deque.back();
}
void push_back(const T& t){
return m_Deque.push_back(t);
}
void push_back(T&& t){
return m_Deque.push_back(std::move(t));
}
void pop_front(){
m_Deque.pop_front();
m_PopCount++;
if (m_PopCount%1024U == 0U){
m_Deque.shrink_to_fit();
}
}
}
template <class T>
using LeanQueue = std::queue<T,DequeAdapter<T>>;
但是请注意,容量的缩减意味着将队列元素移动或复制到新的精简块中,内存消耗会更小,但性能可能会下降。
当队列超出作用域时,队列管理的任何内存都将被释放。
然而,即使这样,内存也可能不会被释放回操作系统,因为标准库假设如果你以前使用过内存,你很可能再次需要它。
这方面的细节是在malloc/free中处理的,在您的程序所链接的特定c运行时库中。
这是一个内存紧张的嵌入式系统吗?(在这种情况下,可以考虑固定大小的容器),或者它是运行在服务器/桌面/ipad上?(在这种情况下,告诉你的老板不要再担心他不明白的事情了。)
对于经常反复使用的容器来说,分配和释放内存可能会造成相当大的开销。因此,容器被允许扩展到它们所使用的范围。如果你想回收内存,你必须显式地执行。这通常涉及允许容器超出作用域,因为标准(出于某种原因)没有提供释放内存的函数。有一个函数可能/可能不释放未使用的内存在一些容器(shrink_to_fit()
),但它不能保证。
你基本上创建一个新的空容器和swap()
它的(空)内容与您的工作容器。
// create a temporary empty container and swap its
// contents with the working container
std::queue<double>().swap(q);
因为pop
只是减小了它的大小,而不是容量。
如果你把其他元素放到队列中,它将不需要分配内存,它只会使用已经分配的内存。
- 将字符串存储在c++中的稳定内存中
- C++ 指针的内存地址和指向数组的内存地址如何相同?
- Win32编译器选项和内存分配
- 当vector是tje全局变量时,c++中vector的内存管理
- 带内存和隔离功能的SQLite
- 是否可以通过C++扩展强制多个python进程共享同一内存
- 迭代时从向量和内存中删除对象
- 不能在初始值设定项列表中将非常量表达式从类型 'int' 缩小到'unsigned long long'
- 在C++中打印指向不同基元数据类型的指针的内存地址
- 这个指针和内存代码打印是什么?我不知道是打印垃圾还是如何打印我需要的值
- 多个文件的内存分配错误"在抛出 'std :: bad_alloc' what (): std :: bad_alloc 的实例后终止调用" [C++]
- 为什么示例代码访问IUnknown中已删除的内存
- 如何在C++类内存结构中创建"spacer"?
- 从构造函数抛出异常时如何克服内存泄漏
- malloc() 可能出现内存泄漏
- 如何理解将半精度指针转换为无符号长指针和相关的内存对齐
- 在调用FreeLibrary后,释放动态链接到具有相同版本的CRT堆的DLL的内存
- 如果正在缩小已分配的内存大小,请同时检查realloc()
- 缩小 std::vector 的大小以适应其实际数据以节省内存使用?vec.swap() 在 MSVC 中不起作用?
- 为什么 std::queue 在弹出元素后不缩小内存?