0 / 0 / 0
Регистрация: 19.04.2013
Сообщений: 19
1

Утечка памяти в WaitForMultipleObjects

15.08.2013, 13:40. Показов 2006. Ответов 20
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Добрый день
Возникла проблема при вызове WaitForMultipleObjects. Каждый раз при ее вызове программа отжирает ~300 килобайт памяти. Т.к. ее вызов повторяется в бесконечном цикле (до завершения программы), то память очень быстро утекает. Подскажите, в чем дело и как с этим бороться?

Ниже часть кода:

Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
procedure TMasterThread.PollJobs;
const
  THIS_METHOD = 'PollJobs';
var
  i         : integer;
  wo_handles: array [0..1] of THandle;
  wo_result : DWORD;
begin
  if m_Jobs.Count = 0 then
    Exit;
 
  wo_handles[0]:= THandle(m_EvTerminate.Handle);
  for i:= 1 to m_Jobs.Count do
    wo_handles[i]:= TReestrThread(m_Jobs.Items[i - 1]).Handle;
 
  wo_result:= WaitForMultipleObjects(m_Jobs.Count + 1, @wo_handles, false, 1000); // <- вот тут утечка памяти
 
...
 
end;
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
15.08.2013, 13:40
Ответы с готовыми решениями:

Утечка памяти
Есть ли в Delphi 6 встроенные глюки, из-за которых может возникать утечка памяти? Конкретно...

Утечка памяти
Друзья, у меня все работает. Вот только не пойму почему приложение в памяти с каждым часом...

ADO в DELPHI (утечка памяти)
Добрый день! Столкнулся с проблемой утечки памяти при использовании компонентов ADO. Вот пример,...

Утечка памяти
Проверил утечку памяти ReportMemoryLeaksOnShutdown , выдало 13 - 20 bytes: UnicodeString x 86 ,...

20
2664 / 2270 / 279
Регистрация: 24.12.2010
Сообщений: 13,723
15.08.2013, 14:25 2
А что, m_Jobs.Count может быть равным только 0 и 1 ?

Судя по

wo_handles: array [0..1] of THandle;

это именно так

Иначе ты не ведаешь что творишь, организуя массив из 2-х хендлов и пытаясь напхать в него более 2-х хендлов при m_Jobs.Count > 1
0
0 / 0 / 0
Регистрация: 19.04.2013
Сообщений: 19
15.08.2013, 14:34  [ТС] 3
Цитата Сообщение от mss Посмотреть сообщение
А что, m_Jobs.Count может быть равным только 0 и 1 ?

Судя по

wo_handles: array [0..1] of THandle;

это именно так

Иначе ты не ведаешь что творишь, организуя массив из 2-х хендлов и пытаясь напхать в него более 2-х хендлов при m_Jobs.Count > 1
Изначально там было:
wo_handles: TWOHandleArray;

Но количество m_Jobs.Count действительно не может превышать 1. На "array [0..1] of THandle" изменил чисто для тестов.
0
2664 / 2270 / 279
Регистрация: 24.12.2010
Сообщений: 13,723
15.08.2013, 14:47 4
Цитата Сообщение от Shelygin Посмотреть сообщение
// <- вот тут утечка памяти
А на основании чего ты сделал умозаключение что именно здесь ?
0
0 / 0 / 0
Регистрация: 19.04.2013
Сообщений: 19
15.08.2013, 14:51  [ТС] 5
Цитата Сообщение от mss Посмотреть сообщение
А на основании чего ты сделал умозаключение что именно здесь ?
Следил в диспетчере задач за выделением памяти. Каждый раз после вызова данной функции программа отжирала ~300 килобайт.
0
2664 / 2270 / 279
Регистрация: 24.12.2010
Сообщений: 13,723
15.08.2013, 15:12 6
и чему при этом был равен wo_result ?
0
0 / 0 / 0
Регистрация: 19.04.2013
Сообщений: 19
16.08.2013, 06:07  [ТС] 7
wo_result = 1
0
2664 / 2270 / 279
Регистрация: 24.12.2010
Сообщений: 13,723
16.08.2013, 09:49 8
То есть якобы есть дождалась завершения треда wo_handles[1]
А сам тред-то по завершению где уничтожается ? Где и как освобождаются занятые им ресурсы ?
0
0 / 0 / 0
Регистрация: 19.04.2013
Сообщений: 19
16.08.2013, 09:58  [ТС] 9
Вот полный текст процедуры:

Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
procedure TMasterThread.PollJobs;
const
  THIS_METHOD = 'PollJobs';
var
  i         : integer;
  wo_handles: array [0..1] of THandle; //TWOHandleArray;
  wo_result : DWORD;
begin
  if m_Jobs.Count = 0 then
    Exit;
 
  wo_handles[0]:= THandle(m_EvTerminate.Handle);
  for i:= 1 to m_Jobs.Count do
    wo_handles[i]:= TReestrThread(m_Jobs.Items[i - 1]).Handle;
 
  wo_result:= WaitForMultipleObjects(m_Jobs.Count + 1, @wo_handles, false, 1000);
 
  case wo_result of
    WAIT_OBJECT_0:
      Exit;
    WAIT_TIMEOUT:
      Exit;
    WAIT_FAILED:
    begin
      LogError(GetLastError, 'WaitForMultipleObjects failed', THIS_METHOD, Self);
      Exit;
    end;
  end;
 
  if (WAIT_OBJECT_0 < wo_result) and (wo_result <= WAIT_OBJECT_0 + m_Jobs.Count) then
  begin
    i:= wo_result - WAIT_OBJECT_0 - 1;
    TReestrThread(m_Jobs.Items[i]).Free;
    m_Jobs.Items[i]:= nil;
    m_Jobs.Delete(i);
  end;
 
  i:= 0;
  while i < m_Jobs.Count do
  begin
    try
      if ((Assigned(TReestrThread(m_Jobs.Items[i]))) and (TReestrThread(m_Jobs.Items[i]).LastActionTime + m_LagLimit > Now())) then
      begin
        LogError(0, 'Задание не проявляет активность: file_id = ' + IntToStr(TReestrThread(m_Jobs.Items[i]).FileId), THIS_METHOD, Self);
        TReestrThread(m_Jobs.Items[i]).Free;
        m_Jobs.Items[i]:= nil;
        m_Jobs.Delete(i);
        Dec(i);
        LogInfo('Задание снято: file_id = ' + IntToStr(TReestrThread(m_Jobs.Items[i]).FileId), THIS_METHOD, Self);
      end;
    except
      on e: Exception do
      begin
        LogError(0, 'Ошибка при проверке задания: file_id = ' + IntToStr(TReestrThread(m_Jobs.Items[i]).FileId) + ' (' + e.Message + ')', THIS_METHOD, Self);
      end;
    end;
 
    Inc(i);
  end;
end;
При вызове
Delphi
1
TReestrThread(m_Jobs.Items[i]).Free;
освобождается немного памяти, но не столько сколько было выделено при запуске WaitForMultipleObjects
0
2664 / 2270 / 279
Регистрация: 24.12.2010
Сообщений: 13,723
16.08.2013, 10:26 10
Ужас какой ..
Заче вообще нужо было задействовать для этого wait-функцию - совершенно не понятно.

Ну вот, к примеру, при wo_result = 1 выражение

begin
i:= wo_result - WAIT_OBJECT_0 - 1;
TReestrThread(m_Jobs.Items[i]).Free;
..
end;

превращается в

begin
i:= 1 - 0 - 1; // i = 0
TReestrThread(m_Jobs.Items[0]).Free; // с чего это вдруг разрушается 0-й тред, если завершился 1-й ?
..
end;
0
0 / 0 / 0
Регистрация: 19.04.2013
Сообщений: 19
16.08.2013, 12:00  [ТС] 11
Цитата Сообщение от mss Посмотреть сообщение
превращается в

begin
i:= 1 - 0 - 1; // i = 0
TReestrThread(m_Jobs.Items[0]).Free; // с чего это вдруг разрушается 0-й тред, если завершился 1-й ?
..
end;
Вроде все верно. Я отправляю в WaitForMultipleObjects два хендла. Первое (wo_handles[0]:= THandle(m_EvTerminate.Handle) указывает на событие, которое сигналит, когда приложение пытаются закрыть. Второе (wo_handles[i]:= TReestrThread(m_Jobs.Items[i - 1]).Handle; // i=1)
В моем случае сигналит второе и WaitForMultipleObjects возвращает 1. Поэтому я освобождаю тред с индексом 0 (собственно он единственный в списке m_Jobs)
0
2664 / 2270 / 279
Регистрация: 24.12.2010
Сообщений: 13,723
16.08.2013, 12:11 12
Цитата Сообщение от Shelygin Посмотреть сообщение
событие, которое сигналит, когда приложение пытаются закрыть
А оно зачем вообще понадобилось ?
Чем флаг Application.Terminated не устроил ?

Добавлено через 5 минут
И вообще я не вижу явной необходимости в ф-ции ожидания ..
По завершению тред может сам сообщить об этом событием OnTerminate. И разрушить сам себя тоже может.
А обнаруживать треды превысившие лимит времени выполнения можно по обычному таймеру ..
0
0 / 0 / 0
Регистрация: 19.04.2013
Сообщений: 19
16.08.2013, 12:26  [ТС] 13
не могу сказать, мне досталось это приложение по наследству. Если не удастся побороть утечку, буду его переписывать (скорее всего на C#). Но я все таки надеюсь, что не придется.

Добавлено через 8 минут
Само по себе приложение, конечно, не идеально, но все равно не понятно под что выделяется память при вызове WaitForMultipleObjects?
0
2664 / 2270 / 279
Регистрация: 24.12.2010
Сообщений: 13,723
16.08.2013, 12:38 14
Как бы там ни было, есть большущие сомнения в "виновности" именно wait-функции.

То есть ты утверждаешь следующее:

// здесь ты вызовом GetProcessMemoryInfo получил WorkingSetSize
wo_result:= WaitForMultipleObjects(..);
// здесь ты повторно получил WorkingSetSize, сравнил его с предыдущим запросом и видишь прирост в 300кб при любом результате, возвращенном ф-цией ожидания

Верно ?
0
0 / 0 / 0
Регистрация: 19.04.2013
Сообщений: 19
16.08.2013, 12:41  [ТС] 15
Нет, я делал проще. Ставил брикпоинт перед вызовом WaitForMultipleObjects. Открывал диспетчер задач и смотрел сколько было выделено памяти до и после вызова.
Прирост я наблюдал только если тред сигналил о завершении.
0
2664 / 2270 / 279
Регистрация: 24.12.2010
Сообщений: 13,723
16.08.2013, 12:51 16
Цитата Сообщение от Shelygin Посмотреть сообщение
Прирост я наблюдал только если тред сигналил о завершении
Ну это ты однократно наблюдал ..
А если в длительном цикле ?
0
0 / 0 / 0
Регистрация: 19.04.2013
Сообщений: 19
16.08.2013, 14:49  [ТС] 17
Неоднократно. У меня там бесконечный цикл.
0
2664 / 2270 / 279
Регистрация: 24.12.2010
Сообщений: 13,723
19.08.2013, 10:29 18
Цитата Сообщение от Shelygin Посмотреть сообщение
У меня там бесконечный цикл
И в том же цикле создается тред ?
0
0 / 0 / 0
Регистрация: 19.04.2013
Сообщений: 19
19.08.2013, 11:21  [ТС] 19
Да, но не на каждой итерации, а только при выполнении определенных условий
0
2664 / 2270 / 279
Регистрация: 24.12.2010
Сообщений: 13,723
19.08.2013, 12:49 20
И все-таки воспользуйся GetProcessMemoryInfo непосредственно до и после вызова wait-ф-ции.
Запиши протокол в файл и приведи его ..
0
19.08.2013, 12:49
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
19.08.2013, 12:49
Помогаю со студенческими работами здесь

Утечка памяти
Доброго времени суток! Подскажите, пожалуйста: Нужно залить много мелких файлов (до 1 Мб)....

Утечка памяти в потоке
Что я делаю не так procedure TMainThredRec.Execute; function BmpToMem(Bmp:TBitmap;var...

Утечка памяти в функции
Добрый вечер, есть функция: function BmpToMem1(Bmp:TBitmap;var W,H:integer):pointer; var ...

WebBrowser и утечка памяти
Есть программа которая циклично заходит на страницы, берёт код страницы и заполняет формы....


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru