目前,我在对象和接口以及它们的内存管理方面遇到了一些问题。我有一个继承自TInterfacedPersistent
的类,名为TAbstractBaseDTO
。我还有一个接口IDuplicatable
,函数function CreateDuplicate: TAbstractBaseDTO
。
我使用接口来实现抽象,而不是管理内存,这就是为什么我使用TInterfacedPersistent
作为祖先类。
Unit.pas
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, System.Actions, Vcl.ActnList,
Vcl.StdCtrls;
type
TAbstractBaseDTO = class abstract (TInterfacedPersistent)
public
constructor CreateEmpty; virtual; abstract;
end;
IDuplicatable = interface
['{153275DC-71C0-4CB6-B933-667419950C68}']
function CreateDuplicate: TAbstractBaseDTO;
end;
TCountryMasterDataDTO = class (TAbstractBaseDTO, IDuplicatable)
public
constructor CreateEmpty; override;
function CreateDuplicate: TAbstractBaseDTO;
end;
TBaseDataForm = class(TForm)
ActionList1: TActionList;
actDuplicate: TAction;
Button1: TButton;
procedure actDuplicateExecute(Sender: TObject);
strict private
var
FDataObject: TAbstractBaseDTO;
function FetchBusinessObject: TAbstractBaseDTO;
public
procedure LoadData(ADataObject: TAbstractBaseDTO);
destructor Destroy; override;
end;
var
BaseDataForm: TBaseDataForm;
implementation
{$R *.dfm}
procedure TBaseDataForm.LoadData(ADataObject: TAbstractBaseDTO);
begin
FDataObject.Free;
FDataObject := ADataObject;
end;
destructor TBaseDataForm.Destroy;
begin
FDataObject.Free;
inherited;
end;
constructor TCountryMasterDataDTO.CreateEmpty;
begin
Create;
end;
function TCountryMasterDataDTO.CreateDuplicate: TAbstractBaseDTO;
begin
Result := TCountryMasterDataDTO.Create;
end;
procedure TBaseDataForm.actDuplicateExecute(Sender: TObject);
var
LAbstractBaseDTO: IDuplicatable;
LAbstractBaseDTODuplicate: TAbstractBaseDTO;
begin
LAbstractBaseDTO := Self.FetchBusinessObject as IDuplicatable;
try
LAbstractBaseDTODuplicate := LAbstractBaseDTO.CreateDuplicate;
Self.LoadData(LAbstractBaseDTODuplicate);
finally
LAbstractBaseDTO := nil;
end;
end;
function TBaseDataForm.FetchBusinessObject: TAbstractBaseDTO;
begin
Result := TCountryMasterDataDTO.Create;
end;
end.
当我运行actDuplicate
action时,FastMM4在关机时报告内存泄漏。
但是,将execute函数更改为:
procedure TBaseDataForm.actDuplicateExecute(Sender: TObject);
var
LAbstractBaseDTO: TAbstractBaseDTO;
LAbstractBaseDTODuplicate: TAbstractBaseDTO;
begin
LAbstractBaseDTO := Self.FetchBusinessObject;
try
LAbstractBaseDTODuplicate := (LAbstractBaseDTO as IDuplicatable).CreateDuplicate;
Self.LoadData(LAbstractBaseDTODuplicate);
finally
LAbstractBaseDTO.Free;
end;
end;
将在运行操作时立即引发访问冲突。
我该如何解决这个问题?
1条答案
按热度按时间kx7yvsdv1#
您遇到的问题是因为存在对已销毁的对象的活动接口引用。
在这种情况下,它是编译器在将
LAbstractBaseDTO
类型转换为IDuplicatable
时创建的隐藏隐式接口引用。这个隐藏的接口引用将被编译器在方法尾声中清除,这将在已经销毁的对象示例上调用
_Release
方法。如果您在完全调试模式下使用FASTMM运行代码,FASTMM将检测到这种情况并显示错误消息,然后是堆栈跟踪:
FASTMM检测到试图使用已释放对象的接口。现在将引发访问冲突以中止当前操作。
为了解决这个问题,你需要将隐式接口引用转换为你可以控制的显式接口引用,然后在释放它引用的对象之前,你可以自己清除这个引用。