Многопоточное приложение и потенциальная утечка памяти (C #)

1

У меня есть консольное приложение, которое запускает задания по расписанию. Работа делает 2 вещи:

1-) Запустите инструкцию SQL 2-) Отправьте по электронной почте результат этого заявления

Если я запускаю задание в последовательной форме, все работает так, как ожидалось, выполняется задание, потребление памяти увеличивается во время операции, а затем освобождается память, однако, если я запускаю задания параллельно, используя параллельную библиотеку задач, после завершения всех заданий, потребление памяти остается намного выше по сравнению с последовательной опцией, а дополнительные задания также продолжают увеличивать потребление памяти.

Чтобы быть более конкретным, я использовал следующие тестовые примеры:

Последовательность: (После того, как цикл завершен и GC собран явно для целей тестирования, потребление памяти составляет около 55 мегабайт)

for (int j = 0; j < 3; j++)
{
    for (int i = 0; i < 15; i++)
    {
        var job = new BIJob(reportData);
        job.Execute();
    }
    Thread.Sleep(10000);
}

Параллельно: (После того, как цикл завершен, и GC собран явно для целей тестирования, потребление памяти составляет около 85 мегабайт)

for (int j = 0; j < 3; j++)
{
    for (int i = 0; i < 15; i++)
    {
        Task jobRunTask = Task.Factory.StartNew(() =>
        {
            var job = new BIJob(reportData);
            job.Execute();

        });
    }
    Thread.Sleep(10000);
}

Разница в потреблении памяти составляет примерно 30 мегабайт после 45 итераций, и дополнительная память не собирается в параллельной версии.

Что может быть причиной такого поведения? Любые идеи/комментарии приветствуются.

  • 0
    Вы уверены, что ваш job.Execute() может обрабатывать многопоточный сценарий?
Теги:
multithreading
memory-leaks
task

2 ответа

1

Когда вы выполняете несколько операций параллельно, вам нужно будет хранить достаточно памяти для работы над каждой из этих параллельных операций, вместо того, чтобы иметь рабочий набор только одного в памяти за раз. У вас также есть дополнительные потоки, каждый из которых будет потреблять память.

Память для этих операций не сможет быть восстановлена до тех пор, пока они не закончатся. Вы только начинаете операции в своем цикле, не дожидаясь их завершения, поэтому они не обязательно даже подходят для сбора всякий раз, когда вы проверяете их. Если вы дождались завершения всех операций, то они будут иметь право на сбор, хотя GC, конечно, может ждать до тех пор, пока он хочет их собирать.

  • 0
    Привет, Servy, я изменил свой параллельный код, чтобы дождаться завершения задач, как показано ниже; однако все еще остается тем же самым, тогда все задачи завершены: List<Task> tasks = new List<Task>(); for (int j = 0; j < 3; j++) { for (int i = 0; i < 15; i++) { Task jobRunTask = Task.Factory.StartNew(() => { var job = new BIJob(reportData); job.Execute(); }); tasks.Add(jobRunTask); } Thread.Sleep(10000); } Task.WaitAll(tasks.ToArray());
  • 1
    @erdem память получает право сбора после задания полного, это не обязательно будет собираться сразу , хотя, и пул потоков потоки , созданные не будут снесены сразу после окончания их использования; они будут постепенно освобождаться, когда они бездействуют. Вы даже не должны беспокоиться об этом вообще. Вы должны беспокоиться о таких проблемах только в том случае, если у вас действительно есть проблемы с вашей памятью, а у вас явно нет.
Показать ещё 4 комментария
0

Параллельная библиотека Task просто сохранит некоторые из потоков, которые она создает, в случае, если она понадобится им позже, потому что создание новых потоков является относительно дорогостоящей операцией (как с точки зрения памяти, так и с процессором).

Что касается утечки памяти: до тех пор, пока нет никакого стресса для ресурсов, нет причин для потока, используемого TPL для освобождения любых потоков. Если вы хотите протестировать утечку памяти, вы можете просто увеличить количество циклов. Не должно быть разницы в использовании памяти после того, как говорят, что цикл повторяется 1000 раз или 1000000 раз.

  • 0
    Это пул потоков, а не TPL, и обратите внимание, что потоки будут освобождены после того, как они некоторое время простаивают.
  • 0
    По умолчанию TPL использует пул потоков. И да, конечно, это освободит их через некоторое время.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню