首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么这个std::queue/指向结构的指针列表直到List.Size() == 0才释放内存?

为什么这个std::queue/指向结构的指针列表直到List.Size() == 0才释放内存?
EN

Stack Overflow用户
提问于 2020-07-01 06:49:49
回答 1查看 299关注 0票数 6

我有一个程序将指向包含cv::mat克隆的结构的指针输入到std::queue/std::list (尝试了这两种方法),其他线程使用。

阅读/创建是快速的,但消耗是缓慢的,因此队列随着时间的推移而增大。

这个队列很大,很容易占用超过50%的系统内存。

当读取/创建停止时,队列会缩小,但是内存不会!

当队列大小最终达到0时,内存几乎立即消失。可以通过确保队列不会弹出最后一个指针来确认queue.size() == 0触发器--内存不会消失。*注:队列仍然存在,没有超出范围,是静态的。

所以我有两个问题:

  1. 为什么当队列的大小为零时内存就消失了?换句话说,为什么当指针被消耗/删除时,内存不消失呢?
  2. 如何显式释放内存?

代码是这样的:

代码语言:javascript
运行
复制
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(队列填充):

代码语言:javascript
运行
复制
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(使用者):

代码语言:javascript
运行
复制
    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 (我认为这是关键点)。
  • 列表/队列只包含指针,因此应该很小。
EN

回答 1

Stack Overflow用户

发布于 2020-07-01 08:13:00

默认情况下,std::queue使用std::deque作为内部容器。当内存被释放时,实现在很大程度上是定义的(当大小达到零时也是如此),但是std::dequestd::vector确实有一个释放多余内存的函数,即shrink_to_fit (c++11功能)。这在std::queue接口中是不可用的,但是可以通过继承来完成(队列中的容器是protected)。

psudocode

代码语言:javascript
运行
复制
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实现,因为您说您也尝试了list,至少在我的版本中,它似乎在删除单个节点时释放内存(正如预期的那样)。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62671148

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档