Delphi 2009 - Может ли свойство интерфейса вызвать утечку памяти?

StackOverflow https://stackoverflow.com/questions/1035915

Вопрос

Я унаследовал приложение 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. Но что касается вашего реального вопроса, да, интерфейсные объекты могут протекать двумя разными способами.

<Ол>
  • Интерфейсы подсчитываются только в том случае, если объекты, которым они принадлежат, реализовали подсчет ссылок в своих методах _AddRef и _Release. Некоторые объекты этого не делают.
  • Если у вас есть круговые ссылки на интерфейс (интерфейс 1 ссылается на интерфейс 2, который ссылается на интерфейс 1), то счетчик ссылок никогда не упадет до 0 без каких-либо специальных уловок с вашей стороны. Если это ваша проблема, я отошлю вас к недавнему сообщению в блоге Андреаса Хаусладена на эту тему.
  • Если вы пропускаете 115 экземпляров этого класса, то это тот класс , который пропускается. Память, занятая этим классом, а не память, занимаемая вещами, на которые он ссылается, протекает. Где-то у вас есть 115 экземпляров TCwcBasicAdapter , которые вы не освобождаете.

    Кроме того, свойства не хранят данные, независимо от того, являются ли они интерфейсами или какими-либо другими типами. Только поля занимают память (наряду с некоторым скрытым пространством, которое компилятор выделяет от имени класса).

    Итак, да, вы лаете не на то дерево. Ваша утечка памяти где-то еще. Когда FastMM сообщает вам, что у вас есть утечка памяти, он также не сообщает вам, где был выделен каждый экземпляр утечки. У него есть такая возможность; вам может потребоваться настроить некоторые символы условной компиляции, чтобы включить эту функцию.

    Конечно, это не только экземпляры этого класса, которые протекают. FastMM также должен сообщать о некоторых других утечках, таких как экземпляры класса или классы, реализующие интерфейс.

    <Ч>

    Основываясь на добавленной вами функции, я начал подозревать, что это действительно TCwcCDSAdapterNavBase , которое протекает, и это может быть из-за нетипичного способа, который вы используете для его создания. Работает ли когда-либо обработчик исключений в GetAdapterNav ? Я сомневаюсь; TObject.GetInterface никогда не вызывает явное исключение. Если объект не поддерживает интерфейс, он возвращает False . Все, что может обработать исключение, это такие вещи, как нарушение прав доступа и недопустимые операции, которые вам действительно не следует ловить в любом случае.

    Вы можете реализовать эту функцию более прямо так:

    if Assigned(FDataSet) then
      Result := TCwcCDSAdapterNavBase.Create(...);
    
    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top