Delphi 10.4中FMX.ListView.TListView重载时内存无法释放问题咨询
解决Delphi 10.4 FMX TListView清空后内存无法释放的问题
核心原因
FMX的TListView调用Clear或逐个Delete项时,部分内部外观对象(如TListItemAppearance派生实例)可能因引用计数未归零、事件绑定未解除,或是组件内部缓存未触发清理,导致内存无法及时释放——哪怕没有位图,自定义外观模板或绑定的事件也可能持有引用。
可行解决方案
1. 强制触发组件资源清理
清空列表后手动调用ReleaseResources,强制释放ListView内部缓存的外观资源;ARC平台(Android/iOS/macOS)可配合重新创建组件彻底清理引用:
if ListView1.Items.Count > 0 then begin ListView1.Items.Clear; // 强制释放内部缓存资源 ListView1.ReleaseResources; {$IFDEF AUTOREFCOUNT} // ARC平台下重新创建组件,彻底清理所有引用 System.TObject.FreeNil(ListView1); ListView1 := TListView.Create(Self); // 恢复原有组件属性(示例:父容器、外观设置) ListView1.Parent := Self; ListView1.Appearance := TListItemAppearance.ClassName; {$ENDIF} end;
2. 手动解除Item的事件绑定
如果ListView项绑定了自定义事件(如OnClick、OnPaint),删除前需解绑事件,避免事件持有对象引用:
var j: Integer; begin for j := ListView1.Items.Count - 1 downto 0 do begin // 解除项的自定义事件绑定(示例:OnClick) ListView1.Items[j].OnClick := nil; // 手动释放外观对象 if Assigned(ListView1.Items.AppearanceItem[j]) then begin ListView1.Items.AppearanceItem[j].Free; ListView1.Items.AppearanceItem[j] := nil; end; ListView1.Items.Delete(j); end; ListView1.ReleaseResources; end;
3. 数据绑定场景的正确清理方式
若使用数据绑定(如绑定TList或TDataSet),不要直接操作Items,先解绑数据源再清空:
// 假设绑定了BindSourceDB1 BindSourceDB1.DataSet := nil; ListView1.Items.Clear; BindSourceDB1.Free; BindSourceDB1 := TBindSourceDB.Create(Self); // 如需复用,后续重新绑定数据源即可
4. 排查自定义Appearance模板
如果用了自定义ItemAppearance模板,确认模板内控件没有持有外部引用,且项删除时模板实例被正确释放。可临时切换回默认Appearance(如ListItem)测试,排查是否为自定义模板导致的泄漏。
验证方法
启用Delphi自带的FastMM4内存泄漏检测(项目选项中开启「Full debug mode」),清空列表后触发内存快照,对比前后内存变化,确认是否仍有未释放对象。
内容的提问来源于stack exchange,提问作者mih
相关产品推荐
相关产品推荐

