簡體   English   中英

Spring4D中的TForm管理

[英]TForm management in 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 ms類型:畫筆手柄句柄:$ 461027f5樣式:BS_SOLID顏色:$ f0f0f0

分配編號:8318程序運行時間:697 ms類型:TSecondary表格地址:$ d51ac64大小:924訪問權限:讀/寫

分配編號:8267程序運行時間:693 ms類型:字體句柄句柄:$ 1d0a28f1面孔:Tahoma高度:-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;

我還嘗試通過以下方式修改TSecondaryForm的OnClose方法:

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

如果您希望通過接口引用計數來處理表單(或從TComponent繼承的任何類),則需要自己實現(請參閱System.TInterfacedObject作為該方法的示例)。

基本上,您需要為要啟用引用的類重新實現IInterface

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

如果要這樣做,請記住,所有者機制不應處理該問題。 如果將其注冊到容器並使用其默認創建機制,則從Spring4D 1.2開始,它將nil傳遞給所有者-請參見Spring.Container.Resolvers.TComponentOwnerResolver )。 在任何版本中,您都需要在DelegateTo內部使用nil顯式創建它。

如果您正在處理通過其父屬性放到其他控件(如框架)上的接口的任何控件,請記住,在這種情況下,另一種內存管理機制將發揮作用,如果該組件的父對象被破壞,則該內存管理機制可能會破壞該組件。 -如果您只是在處理接口表單,那不是問題,但是我想我在這里提到是為了完整性。

TComponent后代(如TForm )禁用接口的引用計數,因此沒有人正在釋放二次形式。 內存模型是基於所有者的,也就是說,當擁有一個對象的父對象被釋放時,它將釋放它的所有子對象。

因此,您可以將所有者傳遞給工廠函數(可能是ApplicationApplication.MainForm )上的表單,並遵循TComponent的內存模型,或者在表單的OnClose事件上添加一個鈎子並將Action設置為caFree 前者將在關閉應用程序時銷毀表單,后者將在第二個表單關閉時銷毀它(盡快)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM