Delphi 2009 - Может ли свойство интерфейса вызвать утечку памяти?
-
10-07-2019 - |
Вопрос
Я унаследовал приложение Intraweb с текстовым файлом утечек памяти объемом 2 МБ, как сообщает FastMM4. У меня это до 115 экземпляров одного класса с утечкой 52 байта.
Краткое описание плохого актера:
TCwcBasicAdapter = class(TCwcCustomAdapter)
protected
FNavTitleField: TField;
function GetAdapterNav(aDataSet: TDataSet): ICwcCDSAdapterNav; override;
public
constructor Create(aDataSource: TDataSource; aKeyField, aNavTitleField: TField; aMultiple: boolean);
end;
и интерфейс:
ICwcCDSAdapterNav = interface(IInterface)
Я лаю не на том дереве, так как это свойство считается ссылкой? Есть ли обстоятельства, при которых свойство интерфейса могло бы предотвратить уничтожение класса?
Вот реализация описанного выше метода:
function TCwcBasicAdapter.GetAdapterNav(aDataSet: TDataSet): ICwcCDSAdapterNav;
var
AdapterNav: TCwcCDSAdapterNavBase;
begin
result := nil;
if Assigned(aDataSet) then begin
AdapterNav := TCwcCDSAdapterNavBasic.Create(aDataSet, FKeyField.Index, FNavTitleField.Index);
try
AdapterNav.GetInterface(ICwcCDSAdapterNav, result);
except
FreeAndNil(AdapterNav);
raise;
end;
end;
end;
с классом, объявленным как:
TCwcCDSAdapterNavBase = class(TInterfacedObject, ICwcCDSAdapterNav)
Решение
FastMM должен дать вам информацию о том, что было обнаружено и где оно было создано.
Это поможет сузить круг до настоящего виновника: кто что пропускает?
Я не уверен, что на самом деле ваш вопрос?
Ваш код неполный или не тот, о котором идет речь: у вашего класса нет ни свойства Interface, ни частного поля Interface, а только метод, который возвращает интерфейс, который безвреден.
Изменить : не видя код вашего объекта, реализующего ICwcCDSAdapterNav, мы не можем определить, действительно ли он подсчитан.
Если вы не выходите из TInterfacedObject , есть вероятность , что он не учитывается, и вы не можете полагаться на это автоматическое освобождение ... р>
Возможно, вы захотите взглянуть на этот сеанс CodeRage 2 : Борьба с утечками памяти для чайников . В основном показано, как использовать FastMM для предотвращения / обнаружения утечек памяти в Delphi. Был для D2007, но все еще актуален для других версий.
Другие советы
У вас есть несколько хороших ответов о том, как работает FastMM. Но что касается вашего реального вопроса, да, интерфейсные объекты могут протекать двумя разными способами.
<Ол> Если вы пропускаете 115 экземпляров этого класса, то это тот класс , который пропускается. Память, занятая этим классом, а не память, занимаемая вещами, на которые он ссылается, протекает. Где-то у вас есть 115 экземпляров TCwcBasicAdapter
, которые вы не освобождаете.
Кроме того, свойства не хранят данные, независимо от того, являются ли они интерфейсами или какими-либо другими типами. Только поля занимают память (наряду с некоторым скрытым пространством, которое компилятор выделяет от имени класса).
Итак, да, вы лаете не на то дерево. Ваша утечка памяти где-то еще. Когда FastMM сообщает вам, что у вас есть утечка памяти, он также не сообщает вам, где был выделен каждый экземпляр утечки. У него есть такая возможность; вам может потребоваться настроить некоторые символы условной компиляции, чтобы включить эту функцию.
Конечно, это не только экземпляры этого класса, которые протекают. FastMM также должен сообщать о некоторых других утечках, таких как экземпляры класса или классы, реализующие интерфейс.
<Ч> Основываясь на добавленной вами функции, я начал подозревать, что это действительно TCwcCDSAdapterNavBase
, которое протекает, и это может быть из-за нетипичного способа, который вы используете для его создания. Работает ли когда-либо обработчик исключений в GetAdapterNav
? Я сомневаюсь; TObject.GetInterface
никогда не вызывает явное исключение. Если объект не поддерживает интерфейс, он возвращает False
. Все, что может обработать исключение, это такие вещи, как нарушение прав доступа и недопустимые операции, которые вам действительно не следует ловить в любом случае.
Вы можете реализовать эту функцию более прямо так:
if Assigned(FDataSet) then
Result := TCwcCDSAdapterNavBase.Create(...);