Delphi - 用10.2.1重新编译应用程序会导致内存泄漏?

13
我刚安装了Delphi 10.2 Release 1。当我重新编译我的应用程序并运行它们时,我发现有很多内存泄漏。在没有更新的情况下,我的10.2版本没有内存泄漏。我也没有更改代码。
为了验证,我创建了一个简单的空白应用程序并在窗体上放置了几个组件。没有代码。运行应用程序并报告了内存泄漏。 Memory leaks from the sample application 我想强调这一点(即使只是作为升级前的警告)。
我的问题:
1.是否有其他人遇到过这个问题? 2.是否有什么我需要或可以做来解决这个问题?
注意:我已经在quality portal上记录了一个问题,以防这是一个真正的问题:https://quality.embarcadero.com/browse/RSP-18774。在这张票中,我还附上了示例应用程序。

似乎 TCalendar 会造成内存泄漏。 - Andrei Galatyn
@AndreiGalatyn 不,我已经测试了没有 TCalendar 的应用程序,但仍然出现了泄漏 :( - zdzichs
我已经使用10.2.1编译了各种应用程序,它们都报告了内存泄漏问题(在升级之前不存在这些问题)。去除日历组件并不能消除内存泄漏。Win32和Win64都编译过了 - 两者都显示内存泄漏。 - Rohit
单个空白表格上的备忘录就足以显示泄漏!但是带有两个按钮、工具栏和速度按钮的表格不会泄漏。对于另一个应用程序,当应用程序处理位图时,我会收到泄漏消息。也许与此有关:http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Multi-Threading_for_TBitmap,_TCanvas,_and_TContext3D? 还有更多:将备忘录的ContolType更改为Platform不会泄漏。 - zdzichs
2个回答

18
经过一些调查,我发现在TStyledControl.KillResourceLink中传递给TThread.CurrentThread.ForceQueue的回调函数从未执行,因为在任何线程处理它们之前,应用程序即将结束并且TThread类析构函数正在销毁仍然有未处理的回调函数的列表。
我通过在FMX.Forms.DoneApplication的结尾处添加对CheckSynchronize的调用来解决这个问题,这会强制执行回调函数,从而解决了内存泄漏问题。
我不知道这是否是此问题的正确修复方法,但它解决了报告的内存泄漏问题。

ForceQueue() 是否使用了空的 AThread 参数?如果是,则在排队线程被释放后,排队的回调将保持活动状态。如果指定了线程对象,则它排队的任何回调都会在自身被释放时被释放。但是,如果销毁队列列表而不销毁列表中的任何项,则这听起来像是排队机制中的错误。向 Embarcadero 提交报告,因为这可能也会影响到 TThread.Queue()ForceQueue() 是 Tokyo 中的新功能,因此这可能只是排队的新实现中的疏忽(我没有 Tokyo,无法验证)。 - Remy Lebeau
1
我是那个要求添加类似于“ForceQueue”功能的人,但我的建议方法与Embarcadero实际实现的方法非常不同。我没有参与它的开发。 - Remy Lebeau
是的,当使用TThread.ForceQueue(nil, ... );时,称其为TThread.CurrentThread.ForceQueue(nil, ... );是多余的。Embarcadero在使用CurrentThread时有点过于热衷(有时甚至不安全)。 - Remy Lebeau
5
顺便提一下,如果 Embarcadero 能测试他们发布的版本就好了,我们需要能够可靠地使用软件(有信心),而不必在应用程序的发布版本中处理此类问题。 - Rohit
1
博客文章“10.2.1中Windows上FMX内存泄漏的解决方法”位于http://blog.marcocantu.com/blog/2017-august-workaround-fmx-memleak.html(感谢Stefan!) - Marco Cantù
显示剩余4条评论

0

我在FMX和VCL应用程序中使用C++Builder 10.2.1时遇到了相同的问题。

如果启用CodeGuard,程序退出时会出现内存泄漏。

我有一个带有OnTerminate处理程序的TThread:如果我在此处理程序中设置断点,关闭程序时它永远不会被调用。

如果我在主应用程序表单的析构函数中放置CheckSynchronize(),问题仍然存在。

我的解决方案是在主窗体的析构函数中使用类似如下的“可怕”循环:

__fastcall TForm3::~TForm3(void) {
    for(int i = 0; i < 10; i++) {
        Sleep(1);
        CheckSynchronize();
    }
}

这个解决方案不是确定性的,但可以在调试模式下用于您的应用程序,以避免 CodeGuard 错误消息。

另一个解决方案是使用 WaitFor() 函数,如果 MyThread 是一个 TThread 对象:

MyThread = new MyThreadClass();

而且 DeleteThisTh() 是这个类的一个方法,我们可以在 DeleteThisTh() 中等待终止的线程:

void MyThreadClass::DeleteThisTh(void) {
    Terminate();
    WaitFor();
    delete this;
}

OnTerminate事件中,我可以清理我的对象。请注意:
  1. delete thisOnTerminate之后被调用;
  2. DeleteThisTh()位于主线程中;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接