You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Delphi中使用对象与接口时的内存泄漏及访问冲突问题求解

Delphi中使用对象与接口时的内存泄漏及访问冲突问题求解

嘿,这个问题我之前也碰到过,核心是TInterfacedPersistent的引用计数机制和手动内存管理的冲突,咱们一步步拆解:

先分析两个问题的根源

1. 第一个代码的内存泄漏

你的第一个actDuplicateExecute里,把FetchBusinessObject创建的对象直接赋值给了接口变量LAbstractBaseDTO。这时候Delphi会自动调用对象的_AddRef方法,把引用计数从0加到1。当你在finally里把LAbstractBaseDTO := nil时,又会调用_Release,引用计数减到0——而TInterfacedPersistent的_Release方法在引用计数为0时会自动调用Destroy销毁对象。

那为什么FastMM报泄漏?大概率是这两个情况之一:

  • CreateDuplicate返回的对象被FDataObject持有,但你的Form在程序退出时没有被正确销毁(比如手动创建的Form没调用Free),导致FDataObject没被释放;
  • 你的TCountryMasterDataDTO.CreateEmpty写法有问题:里面的Create应该改成inherited Create;,否则可能导致对象初始化异常,间接引发泄漏。

2. 第二个代码的访问冲突

你把创建的对象赋值给了普通对象变量LAbstractBaseDTO,然后转成IDuplicatable接口——这时候同样会触发_AddRef,引用计数变成1。然后你在finally里手动LAbstractBaseDTO.Free销毁了对象,但接口变量(那个临时的IDuplicatable)还持有对该对象的引用。当接口变量离开作用域时,Delphi会自动调用_Release,这时候访问的是已经被销毁的内存,直接触发AV。

解决方案:避免混合两种内存管理方式

既然你明确不想用接口管理内存,只想用它做抽象,那就要严格区分手动内存管理和接口引用:

修正后的actDuplicateExecute代码

procedure TBaseDataForm.actDuplicateExecute(Sender: TObject);
var
  LBaseObj: TAbstractBaseDTO;
  LDuplicatable: IDuplicatable;
  LNewObj: TAbstractBaseDTO;
begin
  LBaseObj := Self.FetchBusinessObject;
  try
    // 临时转换为接口,调用方法后立即释放接口引用
    LDuplicatable := LBaseObj as IDuplicatable;
    try
      LNewObj := LDuplicatable.CreateDuplicate;
      Self.LoadData(LNewObj);
    finally
      // 清空接口变量,让引用计数回到初始值(0),不会触发自动销毁
      LDuplicatable := nil;
    end;
  finally
    // 手动销毁原始对象,此时引用计数是0,安全无冲突
    LBaseObj.Free;
  end;
end;

额外的优化建议

  1. 修复TCountryMasterDataDTO.CreateEmpty的写法:
constructor TCountryMasterDataDTO.CreateEmpty;
begin
  inherited Create; // 明确调用父类构造,避免歧义
end;
  1. 确保FetchBusinessObject创建的对象确实是你需要的临时对象——如果只是用来调用CreateDuplicate,那这个临时对象的生命周期要严格控制,避免不必要的内存占用。
  2. 检查Form的销毁逻辑:如果是手动创建的Form,一定要在不用时调用Free,确保FDataObject被正确释放。

这样调整后,既保留了接口的抽象能力,又完全用手动方式管理内存,不会再出现AV和泄漏问题了。

备注:内容来源于stack exchange,提问作者Raphi1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.22 14:15:32