【问题标题】:Free memory of array in Delphi [closed]Delphi中数组的可用内存[关闭]
【发布时间】:2018-09-05 09:42:31
【问题描述】:

在使用 FastMM4 时,函数 DynArraySetLength 中的 system.pas 存在内存泄漏。我正在使用一个列表,其中每个元素都有 5 条记录。这些记录又是几百万的顺序列表。因此,小的内存泄漏累积成巨大的块。

在释放元素时,我故意使用 SetLength(x,0) 和 x:=nil。 但是,system.pas 的 DynArraySetLength 中仍然存在内存泄漏。 有人可以建议我如何使用有效的方式释放数组并解决此内存泄漏问题。

提前致谢

代码: 内存泄漏发生在此过程的 SetLength

 procedure TElem.Assign(Value: TElem);
 begin
 SetLength(Self.aXY.points, Length(Value.aXY.points)); //MEMORY LEAK
 Move(Value.aXY.points[0], Self.aXY.points[0],
 Length(Value.aXY.points) * SizeOf(coordinate));
 end;

释放时我正在使用这个程序:

 procedure TElem.FreeElem;
 begin
 SetLength(Self.aXY.points,0);
 Self.aXY.points:=nil;
 end;

【问题讨论】:

  • x声明及其他相关代码在哪里?
  • 没有实际代码是不可能回答这个问题的。
  • 内存泄漏发生在此过程的 SetLength TElem.Assign(Value: TElem);开始设置长度(Self.aXY.points,长度(Value.aXY.points));移动(Value.aXY.points[0],Self.aXY.points[0],长度(Value.aXY.points)* SizeOf(坐标));结尾;释放时我正在使用这个程序:procedure TElem.FreeElem;开始 SetLength(Self.aXY.points,0); Self.aXY.points:=nil;结束;
  • Move 是低级程序。它没有处理数组元素中正确管理的类型......但我们仍然对元素一无所知。
  • 请添加其他人已经要求的声明,并解释您如何知道存在内存泄漏以及仅在一次数组分配/释放后泄漏的大小是多少?

标签: arrays delphi memory record pascal


【解决方案1】:

动态数组由系统管理并在其作用域结束时自动释放。所以你实际上不需要明确地释放它们。当然,如果您确实希望在它们的作用域结束之前释放它们,您可以这样做。这样做就足够了:

SetLength(aXY.points, 0);

aXY.points := nil;

Finalize(aXY.points);

这三个语句中的每一个都是相同的。你可以选择其中之一,但多做一个是没有意义的。例如,这就足够了:

procedure TElem.FreeElem;
begin
  aXY.points := nil;
end;

这些都不能解释为什么你有泄漏。正如我所解释的,动态数组是托管的,因此当它们的作用域结束时,它们将被销毁。

对此的明显结论是动态数组的范围永远不会结束。如果您的代码泄露了TElem 实例,就会发生这种情况。如果您未能销毁拥有该数组的TElem 实例,则该数组本身不会被销毁,并且会泄漏。

另一个导致泄漏的原因可能是数组的元素本身就是托管类型。 Move 执行“盲”内存复制并绕过数组中任何托管类型的生命周期管理。如果您的数组元素具有托管类型(字符串、动态数组、接口等),那么使用Move 是错误的。

【讨论】:

  • 如果我不得不猜测,我认为您很可能没有破坏 TElem 实例。不要让我们猜测。提供minimal reproducible example
  • FWIW,@alphasin 的信息:而不是 SetLength(A, Length(B)); Move(B[0], A[0], SizeOf()...);,这样做更容易且非常安全:A := Copy(B);。这也适用于托管类型。如果不修改值,即使是简单的A := B; 也可以。
  • @RudyVelthuis 我认为很有可能在名为TElem.Assign 的方法中需要元素的副本。
  • 是的,确实如此。你认为 Copy(dynarray) 是做什么的?或者你的意思是简单的任务?如果实现了 COW(在类中,而不是用于 dynarrays),则可能不需要副本(当时)。仅仅分配 dynaray 引用就足够了。
  • @RudyVelthuis 好吧,这就是Assign 的全部意义,不是吗。您是否曾在 RTL 或 VCL 中看到不进行深拷贝的 Assign 方法?
猜你喜欢
  • 2016-07-25
  • 1970-01-01
  • 1970-01-01
  • 2010-11-23
  • 2013-05-01
  • 1970-01-01
  • 2017-06-26
  • 2012-05-19
  • 1970-01-01
相关资源
最近更新 更多