Я работаю над программой, использующей большое количество потоков, каждый поток выделяет в куче несколько мегабайт памяти. Когда эти потоки заканчиваются, большая часть оперативной памяти сохраняется программой.
Вот пример кода, выделяющего и освобождающего 1 МБ в 500 потоков, который показывает эту проблему:
#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;
}
На моем компьютере этот код, просто созданный с g++ -o exe main.cpp -lpthread
, использует 1976 КБ перед сообщением «Запуск потоков» и 419 МБ после сообщения «Поток завершен». Эти значения являются просто примерами: когда я запускаю программу несколько раз, я могу получить разные значения.
Я пробовал valgrind / memcheck, но он не обнаруживает утечки.
У меня есть заметил, что блокировка операции «std :: fill» с помощью мьютекса, похоже, решает эту проблему (или в значительной степени уменьшает ее), но я не думаю, что это проблема состояния гонки, поскольку здесь нет общей памяти. Я полагаю, что мьютекс просто создает порядок выполнения между потоками, который избегает (или уменьшает) условия, при которых происходит утечка памяти.
Я использую Ubuntu 18.04, с G CC 7.4.0.
Спасибо за вашу помощь.
Аурелиен