多线程程序中意外的内存泄漏

我正在使用大量线程的程序上工作,每个线程在堆中分配几兆字节的内存。当这些线程结束时,程序将保留大部分RAM。

这是一个代码示例,它在500个线程中分配和释放1 MB内存,这显示了此问题:

#include <future>
#include <iostream>
#include <vector>

// filling a 1 MB array with 0
void task() {
    const size_t S = 1000000;
    int * tab = new int[S];
    std::fill(tab, tab + S, 0);
    delete[] tab;
}

int main() {
    std::vector<std::future<void>> threads;
    const size_t N = 500;

    std::this_thread::sleep_for(std::chrono::seconds(5));
    std::cout << "Starting threads" << std::endl;

    for (size_t i = 0 ; i < N ; ++i) {
        threads.push_back(std::async(std::launch::async, [=]() { return task(); }));
    }

    for (size_t i = 0 ; i < N ; ++i) {
        threads[i].get();
    }

    std::cout << "Threads ended" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(25));

    return 0;
}

On my computer, this code, simply built with g++ -o exe main.cpp -lpthread, uses 1976 kB before the message "Starting threads", and 419 MB after the message "Threads ended". These values are just examples: when I run the program multiple times, I can get different values.

我已经尝试过valgrind / memcheck,但是它没有检测到任何泄漏。

我注意到,用互斥锁锁定“ std :: fill”操作似乎可以解决此问题(或在很大程度上减少它),但是我不认为这是竞争条件问题,因为这里没有共享内存。我想互斥锁只是在线程之间创建执行顺序,从而避免(或减少)内存泄漏的情况。

我正在使用带有GCC 7.4.0的Ubuntu 18.04。

谢谢您的帮助。

Aurélien

评论
  • Norma
    Norma 回复

    完全没有内存泄漏,因为Valgrind / memcheck已向您确认。

    在消息“正在启动线程”之前使用1976 kB,在消息“线程结束”之后使用419 MB。

    两件事情:

    • At the beginning, your vector is empty.
    • At the end, your vector contains 500 std::future<void> objects.

    这就是为什么内存消耗增加的原因。一切都是有代价的,您无法免费将某些内容存储在内存中,因此您的程序会按预期运行。

    顺便说一句,您不需要使用lambda,可以直接传递函数:)