【问题标题】:c++ memory leak using threadsc++内存泄漏使用线程
【发布时间】:2014-11-18 12:24:03
【问题描述】:

这段代码有内存泄漏,我不明白为什么。

每个线程都调用函数 exec。函数 exec 只是创建一个 std::vector 然后删除它。这个向量的长度等于线程的数量,它只被创建和删除一次。

您可以假设这段代码是线程安全的,因为向量仅在创建后才被删除。

class Foo{
  public:
  Foo(const std::size_t& numThreads):size_(numThreads){}
  inline void alloc(){std::call_once(bufferflag_,&Foo::alloc_,this);}
  inline void free(){std::call_once(bufferflag_,&Foo::free_,this);}

  private:
  const std::size_t size_;
  std::vector<double>* bufferptr_;
  std::once_flag bufferflag_;

  inline void alloc_(){bufferptr_ = new std::vector<double>(size_);}
  inline void free_(){delete [] bufferptr_;}
};

void exec(Foo& comm){
  comm.alloc();
  // sync the threads here with some barrier
  comm.free();
}

void main(){
  Foo comm(10);
  std::vector<std::thread> t(10);
  for(std::size_t tid=0;tid!=10;++tid) t[tid]=std::thread(exec,std::ref(comm));
  for(std::size_t tid=0;tid!=10;++tid) t[tid].join();
}

堆摘要:

退出时使用:104 个字节,2 个块

总堆使用量:23 次分配,21 次释放,分配 3,704 字节

1 个块中的 104(24 个直接,80 个间接)字节在 2 个丢失记录 2 中肯定丢失了

泄漏摘要:

肯定会丢失:1 个块中的 24 个字节

间接丢失:1 块 80 字节

可能丢失:0 个块中的 0 个字节

仍然可达:0 个块中的 0 个字节

抑制:0 个块中的 0 个字节

更新

如果我不使用 call_once 而只是从同一个线程中调用 new 和 delete,则不会出现内存泄漏。

【问题讨论】:

  • 也许你需要在删除exec函数中的指针之前调用bufferptr.clear()? 80B 是 sizeof(double) * 10
  • 如果我在delete heap之前调用bufferptr_->clear()和泄漏总结是完全一样的。
  • 你如何确保alloc 被调用之前 free
  • 这个程序是一个巨大的竞争条件。
  • 在 alloc 和 free 的调用之间,我使用屏障来同步线程。我没有发布完整的代码,因为它变得冗长且可读性差。您可以添加一个冗长的计算,以确保以正确的顺序调用这两个函数或实现一个屏障来同步线程。

标签: multithreading c++11 memory-leaks new-operator delete-operator


【解决方案1】:

看看这个修改后的代码:

class Foo
{
public:
    Foo(const std::size_t& numThreads) :size_(numThreads) {}
    inline void alloc()
    {
        printf("alloc\n");
        std::call_once(alloc_flag, &Foo::alloc_, this);
    }
    inline void foo_free()
    {
        printf("free\n");
        std::call_once(free_flag, &Foo::free_, this); // Changed from bufferflag
    }
private:
    const std::size_t size_;
    std::vector<double>* bufferptr_;
    std::once_flag alloc_flag;
    std::once_flag free_flag;

    inline void alloc_()
    { 
        printf("once_alloc_!\n");
        bufferptr_ = new std::vector<double>(size_);
    }
    inline void free_()
    { 
        printf("once_free_!\n");
        bufferptr_->clear();
        delete bufferptr_; // Not delete[] bufferptr_
        bufferptr_ = NULL;
    }
};

void exec(Foo& comm){
    comm.alloc();
    // Barrier
    comm.foo_free();
}

如果您对 alloc 和 free 使用 2 个不同的 once_flag,您还可以运行 free_() 方法。您只使用一个标志这一事实会产生内存泄漏,因为该标志被第一个分配器使用

为了检查内存泄漏,我使用_CrtDumpMemoryLeaks();,即使我注释掉线程创建/加入例程,我也会得到一些额外的泄漏,但我认为这是 std::vector thrash。希望这会有所帮助!

【讨论】:

    猜你喜欢
    • 2020-08-08
    • 1970-01-01
    • 2014-10-29
    • 2013-12-18
    • 1970-01-01
    • 2021-05-23
    • 2017-02-04
    • 2016-12-09
    • 2012-02-17
    相关资源
    最近更新 更多