Управление TForm в Spring4D

У меня есть следующий код:

Project.dpr

program Project2;

uses
  madExcept,
  madLinkDisAsm,
  madListHardware,
  madListProcesses,
  madListModules,
  Spring.Container,
  Vcl.Forms,
  uRegistrations in '..\Memory leak II\uRegistrations.pas',
  Unit3 in 'Unit3.pas' {MainForm},
  Unit4 in 'Unit4.pas' {SecondaryForm},
  Unit5 in 'Unit5.pas';

{$R *.res}

begin
  RegisterTypes(GlobalContainer);
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
//  MainForm:=TMainForm.Create(nil);
  Application.CreateForm(TMainForm, MainForm);
  MainForm.SecondaryForm := Globalcontainer.Resolve<ISecondaryForm>;
  Application.Run;
end.

uRegistrations.pas, который регистрирует интерфейс

unit uRegistrations;

interface

uses
  Spring.Container;

procedure RegisterTypes(Container: TContainer);

implementation

uses
  Unit5,
  Unit4;

procedure RegisterTypes(Container: TContainer);
begin
  container.RegisterType<ISecondaryForm, TSecondaryForm>.DelegateTo(
    function: TSecondaryForm
    begin
      result := TSecondaryForm.Create(nil);
    end);
  Container.Build;

end;

end.

Unit3.pas держит основную форму

unit Unit3;

interface

uses
  Winapi.Windows,
  Winapi.Messages,
  System.SysUtils,
  System.Variants,
  System.Classes,
  Vcl.Graphics,
  Unit5,
  Vcl.Controls,
  Vcl.Forms,
  Vcl.Dialogs;

type
  TMainForm = class(TForm)
  private
    { Private declarations }
    FSecondaryForm: ISecondaryForm;
  public
    { Public declarations }
    property SecondaryForm: ISecondaryForm read FSecondaryForm write FSecondaryForm;
  end;

var
  MainForm: TMainForm;

implementation

{$R *.dfm}

end.

Unit4.pas со вторичной формой

unit Unit4;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  unit5,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs;

type
  TSecondaryForm = class(TForm, ISecondaryForm)
  private
    { Private declarations }
  public
    { Public declarations }
  end;

//var
//  SecondaryForm: TSecondaryForm;

implementation

{$R *.dfm}

end.

и, наконец, Unit5.pas с объявлением интерфейса

{$M+}
unit Unit5;

interface

type
ISecondaryForm=interface
  ['{62D63E9A-A3AD-435B-8938-9528E70D78B1}']
end;

implementation

end.

Он компилируется и запускается регулярно, но когда я закрываю приложение, у меня три утечки памяти.

номер выделения: 8482 время выполнения программы: 721 мс тип: дескриптор кисти: $461027f5 стиль: BS_SOLID цвет: $f0f0f0

номер выделения: 8318 время работы программы: 697 мс тип: TSecondaryForm адрес: $d51ac64 размер: 924 права доступа: чтение / запись

номер выделения: 8267 время запуска программы: 693 мс тип: дескриптор дескриптора шрифта: $1d0a28f1 грань: высота тахомы: -11

Почему это происходит и как я могу решить это?

РЕДАКТИРОВАТЬ

После ответа я реализовал следующие решения (в комментариях отмечены ошибки, которые я получил:

procedure RegisterTypes(Container: TContainer);
begin
  container.RegisterType<ISecondaryForm, TSecondaryForm>.DelegateTo(
    function: TSecondaryForm
    begin
      result := TSecondaryForm.Create(nil);

      result.Owner:=Application.MainForm;//cannot assign to a read-only property
      result.Parent:=Application; //incompatible types
      result.Parent:=application.MainForm;//memory leak

    end);
  Container.Build;

end;

Я также попытался изменить метод OnClose для TSecondaryForm следующим образом:

procedure TSecondaryForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action:=caFree; //memory leak
end;

но у меня утечка памяти.

Что я делаю не так со всей техникой выше?

В конце я просто сделал два метода _AddRef и _Release для управления подсчетом ссылок, как это было предложено в комментариях, и у меня больше нет утечек памяти.

  TSecondaryForm = class(TForm, ISecondaryForm)
  private
    { Private declarations }
  protected
    FRefCount: Integer;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
  public
    { Public declarations }
  end;

function TSecondaryForm._AddRef: Integer;
begin
  Result := InterlockedIncrement(FRefCount);
end;

function TSecondaryForm._Release: Integer;
begin
  Result := InterlockedDecrement(FRefCount);
  if Result=0 then
    self.Free;
end

2 ответа

Решение

Если вы хотите, чтобы форма (или любой класс, унаследованный от TComponent) была обработана путем подсчета ссылок интерфейса, вам нужно реализовать ее самостоятельно (посмотрите на System.TInterfacedObject как пример как это сделать).

Вам в основном нужно переопределить IInterface к классу, на который вы хотите включить подсчет ссылок:

type
  TInterfacedForm = class(TForm, IInterface)
    // look at System.TInterfacedObject
  end;

Если вы делаете это, имейте в виду, что это не должно обрабатываться механизмом владельца. Если вы зарегистрируете его в контейнере и используете его механизм создания по умолчанию, он передаст nil владельцу начиная с Spring4D 1.2 - см. Spring.Container.Resolvers.TComponentOwnerResolver). В любой версии, прежде чем вам нужно явно создать его с нуля внутри DelegateTo,

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

TComponent потомки (как TForm) отключить подсчет ссылок на интерфейсы, поэтому никто не освобождает вторичную форму. Модель памяти основана на владельце, то есть, когда освобождается родительский объект, которому принадлежит объект, освобождаются все его дочерние элементы.

Таким образом, вы можете передать владельца в форму на заводской функции (возможно, Application, или же Application.MainForm) и придерживаться модели памяти TComponent или добавить хук на OnClose событие формы и множества Action в caFree, Первый уничтожит форму при закрытии приложения, а второй уничтожит ее, как только будет закрыта вторичная форма (как можно скорее).

Другие вопросы по тегам