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.





