Delphi→ Утечка памяти в IEnumVARIANT

Май 11, 2011


При работе с перечислениями IEnumVARIANT было замечено странное поведение — каждая итерация с получением следующего элемента IEnumVARIANT.Next приводила к увеличению размера в памяти, занимаемого приложением. После каждых 1000 итераций размер увеличивался на 2 Мб, а это очень критично когда программа должна работать продолжительное время.

Это как раз мой случай, т.к. я разрабатывал сервис, который постоянно запущен, даже если пользователь не зашел в систему под своими учетными данными. Данная утечка могла бы к концу дня полностью повесить систему, поэтому в течении нескольких часов я кропотливо проверял каждую строчку своего кода, дабы найти эту утечку. Путем перебора было определено, что утечку дает, как я уже говорил, функция IEnumVARIANT.Next. Например, в следующем листинге представлен код с утечкой:

uses
  SysUtils, ActiveX;

var
  FEnum: IEnumVARIANT;
  FVariant: OleVariant;
  FCount: Cardinal;
  FIndex: integer;

begin
  FIndex := 0;
  while (true) do
  begin
    if FEnum.Next(1, FVariant, FCount) <> S_OK then Break; // Здесь утечка
    Inc(FIndex);
  end;
  WriteLn(IntToStr(FIndex));
  FEnum := nil; // Используйте вместо метода _Release
end.


Когда происходит второй вызов функции Next и при этом переменная FVariant (OleVariant) содержит какое-либо значение, происходит утечка. Предыдущее значение FVariant не затирается, а остается в памяти. Поэтому, перед тем как производить запись в FVariant, нужно очистить эту переменную. Исправленная версия кода (без утечки) будет выглядеть так:

uses
  SysUtils, ActiveX, Variants;

var
  FEnum: IEnumVARIANT;
  FVariant: OleVariant;
  FCount: Cardinal;
  FIndex: integer;

begin
  FIndex := 0;
  while (true) do
  begin
    if not VarIsNull(FVariant) then FVariant := Unassigned; // Обнуление переменной
    if FEnum.Next(1, FVariant, FCount) <> S_OK then Break; // Утечки больше нет
    Inc(FIndex);
  end;
  WriteLn(IntToStr(FIndex));
  FEnum := nil;
end.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *