为什么这个 std::queue/指向结构的指针列表直到 List.Size() == 0 才释放内存?
Why does this std::queue/list of pointers to structs not free memory until List.Size() == 0?
我有一个程序,它将指向包含 cv::mat 克隆的结构的指针馈送到其他线程使用的 std::queue/std::list(尝试了两者(。
读取/创建速度很快,但消耗速度很慢,因此队列的大小会随着时间的推移而增长。
此队列变得巨大,很容易占用>50% 的系统内存。
当读取/创建停止时,队列会缩小,但内存不会!
当队列大小最终达到 0 时,内存几乎立即消失。queue.size(( == 0 触发器可以通过确保队列永远不会弹出最后一个指针来确认 - 内存不会消失。 *注意:队列仍然存在,它没有超出范围,这是静态的。
所以我有两个问题:
-
为什么队列达到零大小时内存消失?或者换句话说,为什么内存不会随着指针被消耗/删除而消失?
-
如何显式释放内存?
代码是这样的:
struct MyStruct {
cv::mat matA;
~MyStruct(){
cout << "Yeah, destructor is called!" << endl;
//matA.release(); //Not needed, right? Adding it does not change anything.
}
};
static queue<shared_ptr<MyStruct>> awaitingProcessing;
static mutex queueGuard;
线程 1(队列填充器(:
BYTE* buffer = (BYTE*)malloc(dataWidth*dataHeight);
while(signal){
LoadData(buffer);
cv::Mat data = cv::Mat(dataHeight, dataWidth, CV_8U, buffer);
auto addable = shared_ptr<MyStruct>(new MyStruct())>;
addable->matA = data.clone();
lock_guard<mutex> guard(queueGuard);
awaitingProcessing.push(addable);
}
线程 2(使用者(:
shared_ptr<MyStruct> pullFromQueue(){
lock_guard<mutex> guard(queueGuard);
if (awaitingProcessing.size() > 0){
auto returnable = awaitingProcessing.front();
awaitingProcessing.pop();
return returnable;
}
return nullptr;
}
void threadLogic(){
while (!interruptFlag){
auto ptr = pullFromQueue();
if (ptr == nullptr){
usleep(5);
}
else{
doSomething(ptr);
}
// ptr destructor called here, as refcount properly hits zero
}
}
如果我没记错的话,std 数据收集通常不会释放它们的内存并将其保留为保留,以防大小再次增长。但是,此集合(队列和/或列表(由指针组成,因此即使队列变大,内存占用也应该很小。
我不熟悉OpenCV的内存管理,但它似乎正在做类似的事情。暂停队列填充允许队列大小缩小,但内存不会缩小。然后,恢复填充会增加队列大小,而不会增加内存大小。
总结几个关键点:
内存- 确实会在不更改范围的情况下释放(即不是内存泄漏(
- 仅当队列大小达到零时,内存才会释放。如果队列大小永远保持在 1,则不会释放
- 结构被破坏
- 结构包含克隆的 cv::mats(我认为这是关键点(
- 列表/队列仅包含指针,因此应该很小
std::queue
默认使用std::deque
作为内部容器。当内存被释放时,实现在很大程度上被定义(当大小达到零时可能是这种情况(,但std::deque
和std::vector
确实具有释放多余内存的功能,即shrink_to_fit
(c ++ 11功能(。这在std::queue
接口中不可用,但可以通过继承来完成(队列中的容器是protected
(。
伪代码:
template<class T>
struct shrinkable_queue : public std::queue<T> {
void shrink_to_fit() {c.shrink_to_fit();}
};
您也可以使用std::queue<T, std::list<T>>
。我确实检查了 MSVC 实现,因为您说您也尝试了列表,至少在我的版本中,即使在删除单个节点(如预期的那样(时,它似乎也会解除分配内存。
- 使用std::multimap迭代器创建std::list
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- C++,OpenCV,尝试显示图像时"OpenCV(4.3.0) Error: Assertion failed (size.width>0 && size.height>0)"此错误
- 如何在 C 中正确使用 libiconv 使其不会报告"Arg list too long"?
- C++中带有List类的迭代器Segfault
- 使用"std::unordereded_map"映射到"std::list"对象
- 大于65535的C++数组[size]引发不一致的溢出
- GCC对可能有效的代码抛出init list生存期警告
- 为什么(-1)%vector::size()总是返回0
- 在for循环中使用auto vs decltype(vec.size())来处理字符串的向量
- 使用std::list创建循环链表
- 重载Singly Linked List中的赋值运算符
- 为什么这个 std::queue/指向结构的指针列表直到 List.Size() == 0 才释放内存?
- 调用 list.size() 方法给出错误"expression must have class type"
- std::list.size() 如何具有恒定的复杂性?
- 如何修复'Size of list( a class) is unknown or zero error'和"声明语法错误"?
- 为什么 std::list.size() 不是恒定时间?
- 使用 list::size() 后运行时间显著增加
- 为什么GCC中std::list O(n)的size()方法
- std::queue<T, list<T> >::size() 在 O(n) 中很慢?