这是关于我继承一个Intraweb应用程序的另一篇文章,该应用程序有一个2MB的内存泄漏文本文件,正如FastMM4所报告的那样,我把它归结为115个实例,每个类泄漏52个字节。
泄漏来自一个相当复杂的实例化和类的处理。需要每个类的实例化才能使应用程序正常运行。所以我正在寻找一些方法来克隆该类,通过克隆的一些直接清理,或以不同的方式引用,或者......?
类的第一个实例化(TCwcBasicAdapter)是一个局部变量,它被添加到TObjectList(不是Owning)并使用TObjectList(FCDSAdapters)销毁:
procedure TCwcDeclaration.AttachAdapter(DS: TDataSource; const FormName, KeyFN, TitleFN: string; const Multiple: boolean = False;
const AllowAttachment: boolean = False; const AllowComment: boolean = False);
var
Forms : TCwcSessionForms;
Adapter: TCwcCDSAdapter;
KeyField, TitleField: TField;
begin
Forms := GetForms(FormName);
KeyField := DS.DataSet.FindField(KeyFN);
TitleField := DS.DataSet.FindField(TitleFN);
Adapter := TCwcBasicAdapter.Create(DS, KeyField, TitleField, Multiple);
Adapter.AttachDBPersist(Self.DBPersist);
Forms.AttachDataAdapter(Adapter);
Forms.SetAllowAttachments(AllowAttachment);
Forms.SetAllowComments(AllowComment);
end;
procedure TCwcSessionForms.AttachDataAdapter(aCDSAdapter: TCwcCDSAdapter);
var
Index: integer;
begin
if (FCDSAdapters.IndexOf(aCDSAdapter) -1)
then raise Exception.CreateFmt('Duplicate Adapter attempting to be attached on %0:s', [FFormClassName]);
Index := FCDSAdapters.Add(aCDSAdapter);
if (FDefaultAdapterIndex = -1)
then FDefaultAdapterIndex := Index;
end;
该类的第二个实例化也是一个局部变量,它被添加到TObjectList(不是Owning)并使用TObjectList(FAdapters)销毁:
procedure TCwcCDSMulticastList.InitializeAdapters(const aSessionForms: TCwcSessionForms);
var
i, Count: integer;
Adapter: TCwcCDSAdapter;
TempMulticast: TCwcCDSEventMulticast;
begin
Count := aSessionForms.GetDataAdapterCount;
for i := 0 to Pred(Count) do begin
Adapter := aSessionForms.GetDataAdapter(i);
TempMulticast := FindDataSource(Adapter.DataSource);
if (TempMulticast = nil) then begin
TempMulticast := TCwcCDSEventMulticast.Create(Adapter.DataSource);
try
FMulticastList.Add(TempMulticast);
except
FreeAndNil(TempMulticast);
raise;
end;
end;
TempMulticast.AddObserver(Adapter);
FAdapters.Add(Adapter);
end;
end;
该类的第三个实例化是上面TempMulticast.AddObserver(Adapter)行的观察者模式的一部分。观察者被添加到TObjectList FObservers(Owning):
procedure TCwcCDSEventMulticast.AddObserver(const aCDSAdapter: TCwcCDSAdapter);
begin
FObservers.Add(TCwcCDSAdapterObserver.Create(aCDSAdapter));
end;
constructor TCwcCDSAdapterObserver.Create(const aCDSAdapter: TCwcCDSAdapter);
begin
inherited Create;
FOnStateChange := aCDSAdapter.OnStateChangeIntercept;
FOnAfterDelete := aCDSAdapter.AfterDeleteIntercept;
FInvalidateCursors := aCDSAdapter.InvalidateCursors;
end;
TCwcBasicAdapter在这里泄露,在FObservers被销毁时没有清理。
我尝试过的最新事情是将FObservers改为不拥有,为适配器创建一个私有字段,释放TCwcCDSAdapterObserver.Destroy中的私有字段,但这会导致错误。
谢谢,
保罗·赖斯答案 0 :(得分:1)
如果列表不是所有者,则在释放列表时它们不会释放对象。只是在每个项目上调用Remove也不会这样做。您必须遍历列表并在列表中的每个项目上调用Free,然后释放列表本身。
如果您创建列表所有者,那么当您释放列表时,他们会为您执行此操作。
for i := 0 to FAdapters.Count do Free(FAdapters[i]);
FreeAndNil(FAdapters);
答案 1 :(得分:0)
你意识到你可以自己处理物品而不让它们的主人自动处理它们?我问这个问题,因为感觉就像你试图让自动装置在所有情况下都能完成工作。