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.