我写了一个使用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 pushing\n");
while(!the_queue.empty())
{
the_queue.pop();
}
printf("Done popping\n");
Run Code Online (Sandbox Code Playgroud)
我将2个断点放在printf("Done pushing\n");并且printf("Done popping\n");在命中断点时检查程序的内存使用情况(在任务管理器中显示).在Done pushing,内存使用量约为34 MB,但Done popping内存使用量仍为~34 MB.这让我感到惊讶!
为什么是这样?有没有办法克服这个问题?
基本上std::queue是一个适配器容器 - 它本身不是一个容器,而是一个围绕其他容器的薄包装器.
例如,让我们看一下队列签名:
template <class T, class Container = deque<T> > class queue;
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,T是存储在队列中的元素的类型,并且Container是底层容器.
这就是你的问题的答案:不同的容器处理内存的方式不同.潜在的双端队列可能会缩小,也可能不会缩小,但是由deque内部来决定.
你也可以std::list用作底层容器.在这种情况下,每个pop删除基础列表节点内存.
您也可以自己编写或修改现有容器以匹配您自己的内存管理模式.你的容器需要支持的一些方法(如吮吸push_back,pop_front),你可以在相关的在线文档中读取.
以下是deque适配器的示例,该适配器每1024个pop调用收缩一次:
template<class T>
class DequeAdapater{
private:
std::deque<T> m_Deque;
size_t m_PopCount;
public:
DequeAdapater():
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,DequeAdapater<T>>;
Run Code Online (Sandbox Code Playgroud)
但请注意,容量缩小意味着将队列元素移动或复制到新的瘦块,内存消耗将会更小,但性能可能会下降.
当队列超出范围时,队列管理的任何内存都将被释放.
但是,即使这样,内存也可能无法释放回操作系统,因为标准库假设如果您之前使用过内存,则可能需要再次使用它.
在程序链接的特定c运行时库中,malloc/free中将详细说明这一点.
这是一个内存紧张的嵌入式系统吗?(在这种情况下可能考虑固定大小的容器),还是在服务器/桌面/ ipad上运行?(在这种情况下告诉你的老板不要担心他不理解的事情).