【问题标题】:FastMM reports memory leak for record thread variableFastMM 报告记录线程变量的内存泄漏
【发布时间】:2013-08-22 08:07:00
【问题描述】:

FastMM 报告以下代码 sn-p 的内存泄漏 (UnicodeString),该代码使用带有字符串的记录线程变量:

program Project10;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  FastMM4,
  System.SysUtils;

type
  TContext = record
    Value : String;
  end;

threadvar
  Context : TContext;

begin
Context.Value := 'asdfsdfasfdsa';
end.

这是真正的内存泄漏,还是在 FastMM 检查内存泄漏后才清理线程变量?

更重要的是:我如何才能抑制报告这些“内存泄漏”,因为它们会混淆可能发现的任何其他内存泄漏?

【问题讨论】:

  • 我相信线程必须清理动态值?尝试在线程清理代码中添加 Context.Value := ''。
  • 这是我的日志代码的一部分,所以我无法控制线程清理,因为这可能会从任何线程调用。
  • 如果你无法访问线程,那你为什么要使用线程变量开始呢?你到底在用它们做什么?由于您不控制线程,我知道检测线程终止的唯一其他方法是编写和加载 DLL,以便您可以接收DLL_THREAD_DETACH 通知。但随后 DLL 将需要管理线程变量内存,除非您跨 DLL 边界共享 FastMM。
  • @Remy 在这种情况下您不需要共享 FastMM。 DLL 将是微不足道的。加载它并调用它导出的函数,传递回调以接收通知。然后这些通知可以在主机的上下文中运行。
  • @DavidHeffernan 我试过了,它确实报告了 XE2 的泄漏。请注意,我包括 FastMM4 单元。

标签: delphi memory-leaks delphi-xe2 fastmm


【解决方案1】:

这是一个真正的泄漏。线程局部变量超出范围时未最终确定。由于您的记录包含一个托管字段,即字符串字段,因此如果记录未最终确定,则与该字符串关联的堆分配内存会泄漏。

documentation 明确指出这一点:

通常由 编译器(长字符串、宽字符串、动态数组、变体、 和接口)可以用threadvar声明,但编译器不会自动释放堆分配的 每个执行线程创建的内存。如果你使用 线程变量中的这些数据类型,这是你的责任 从线程中处理他们的内存,之前 线程终止。

如果您想堵住漏洞,您需要在作用域结束时最终确定变量。也就是说,线程正在终止。

Finalize(Context);

请注意,您必须从拥有该变量的线程执行此代码,因为显然只有该线程可以访问它。

如果您想禁止报告这些泄漏,请调用 RegisterExpectedMemoryLeak。

如果在线程终止时无法执行代码,那么最好避免堆分配并使用固定长度的字符数组。很可能满足您的需求。

您声称在线程终止时无法执行代码似乎很奇怪。如果你不能这样做,你怎么能在这些线程的上下文中执行任何代码。换句话说,为了发生泄漏,您必须在这些线程中执行您的代码。

【讨论】:

  • 嗨大卫,请看我对这个问题的评论......在我看来,我无法知道线程何时终止,因为我无法控制这些线程。
  • 如果你想避免泄露这些字符串,那么你需要改变你的设计。我添加了一些建议。
  • 我还没有决定要做什么(RegisterExpectedMemoryLeak 不是一个选项,因为我不知道有多少泄漏,这取决于记录某些内容的线程数)。我会将我的问题留待一段时间,以便其他人也可以做出贡献,然后我会接受答案。
【解决方案2】:

创建 TContext 的全局数组,然后将属于您的线程的元素的索引存储在 threadvar 中。

【讨论】:

  • 这实际上并没有回答问题。但即便如此,你打算如何处理这个全局数组?等到终止,然后完成所有记录?在这种情况下,它与 RegisterExpectedMemoryLeak 相同。或者你的意思是用这个数组做其他事情。哦,显然对数组的访问必须同步。这会损害性能。
  • 我认为不需要同步整个数组,因为每个线程只会修改一个元素。
  • @Fabricio 创建新线程并且必须重新调整数组大小时会发生什么?
  • @DavidHeffernan:这是唯一需要它的场合,我敢打赌这将是一个罕见的事件。如果你创建了 100 个(在一个荒谬的例子中)线程,并且完成了 20 个线程,那么当需要一个新线程时,你不需要调整数组的大小。
  • @Fabricio 这不是我处理多线程编码的方式。希望不太可能的事件不会发生。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-17
  • 2011-12-05
  • 2015-04-05
相关资源
最近更新 更多