当前FastMM版本与Delphi XE默认版本的比较

3
我们在Delphi XE中处理第三方组件线程代码的方式出现了问题。我说第三方是因为我们的核心应用程序没有自己实现任何多线程代码。我已经确定,如果我使用SimpleShareMem(我们有几个dll与主应用程序共享字符串数据),则会发生奇怪的内存损坏,但是如果我安装FastMM4单元,则这些错误将消失。我指的是这些错误很少是两次相同的,尽管它们在同一区域。我最初安装FastMM4是为了尝试确定错误的原因,但事实上,当它被安装时,它们根本不会发生。我在我的选项集中设置了条件,允许我在项目组中的所有模块之间轻松切换SimpleShareMem和FastMM,并可以很容易地证明我的结论。
我的即时示例是TRichView。我已经发现,当我启用hunspell拼写检查器时,我可以通过同时粘贴并向上点击滚动多次(需要执行多少次不同),在PaintBuffered / PaintTo过程中产生错误或附近。有时它是外部异常,解决为表面异常,其他时候我在异常处理代码中达到堆栈溢出。
我遇到的另一个例子是AnyDAC(DA-SOFT)远程/文件监视系统,也在单独的线程中运行,它不能使用SimpleShareMem,但使用FastMM4可以正常工作。
基于这些经验,我被迫在生产构建中使用FastMM4单元,尽管这对我来说似乎很奇怪。当然,我总是首先怀疑自己的代码,所以我想知道是否有什么我可以做来加剧这个问题,尽管FastMM4没有显示主应用程序具有任何堆栈损坏等。
因此,我的问题是,有人能想到为什么FastMM4会比Delphi XE使用的任何版本的FastMM更适合多线程操作吗?
更新:我想添加的是,我现在已经使用旧的Sharemem / borlndmm.dll概念进行了一些测试,也可以正常工作。
更新2:感谢您的建议。我一直在努力找到导致我的问题的Heisenbug,但几乎没有成功。我有一个额外的观察结果。
如果我修改主应用程序,使其不加载需要ShareMem的DLL,则无论我使用哪个内存管理器,都不会出现AnyDAC日志记录或TRichView的问题。即使我不调用该dll,加载该DLL(启动FastMM的初始实例并与主应用程序共享)也会导致问题。接下来我要做的是修改主应用程序以启用该dll的动态加载(从而强制内存管理器安装到主应用程序中),看看是否有所不同。

更新3: 动态加载dll与不加载它具有相同的效果...一切正常运作。


所有项目都共享MM吗?我必须说,我对你的代码有所怀疑,并且仅仅因为完整的FastMM使问题看起来消失了,并不意味着你真正修复了它。 - David Heffernan
是的,所有项目都在共享 MM(内存管理器)。我非常小心地确保它要么是 SimpleShareMem,要么是 FastMM4,同时将条件应用于所有项目的选项集中。并且我同意你的观点,这不是一种让我感到满意的“修复”方法。 - Dan Hacker
你是否在使用带有LARGEADDRESSAWARE的64位机器?某些代码可能会在这种情况下失败,但使用不同的MM可能会隐藏该问题。 - David Heffernan
我们所有的模块都是在XE下编译的。 - Dan Hacker
在这种情况下,我认为你的代码有一个错误。 - David Heffernan
显示剩余3条评论
1个回答

5

Delphi XE内嵌的内存管理器是FastMM4的简化版本。

内存块分配器本身是相同的,但共享机制不同。

默认情况下,在FastMM4Options.inc中设置了以下条件:

{Define this to enable backward compatibility for the memory manager sharing
 mechanism used by Delphi 2006 and 2007, as well as older FastMM versions.}
{$define EnableBackwardCompatibleMMSharing}

它将为库创建一个隐藏的窗口句柄,以检索共享内存管理器实例 - 这是Delphi 2006和2007的工作方式。自Delphi 2009以来,在GetMem.inc中实现的FastMM4精简版中已经不存在此类共享 - 它仅实现了共享内存管理器文件映射(这是新方法)。其中一个库可能需要旧版本的内存管理器共享,无法找到共享的内存管理器实例,因此使用自己的内存分配器 - 并在处理共享内存(如 string 实例)时失败。这是我发现的两个版本之间唯一的区别,这可能是您的程序中共享不起作用的原因。您可能有一些使用Delphi 2006或2007编译的库,并且Embarcadero已弃用了共享方法(以节省一些代码字节?)。

我正在运行FastMM4测试,但没有在FastMM4Options.inc中定义EnableBackwardCompatibleMMSharing。不过感谢您的关注。 - Dan Hacker
你尝试设置NeverSleepOnThreadContention变量了吗?是的,我知道它不是很好(http://www.thedelphigeek.com/2011/09/neversleeponthreadcontentionnot.html),但也许值得一试?FastMM4条件定义是否已设置?两个版本的所有代码都听起来相等。只有条件可能会有所不同。 - Arnaud Bouchez
@Arnaud,“NeverSleepOnThreadContention”不会影响正确性。 - David Heffernan
@DavidHeffernan 这确实会影响速度;在多线程中,由于额外的延迟,很难确定是否存在边界副作用。也许还有其他选项?我没有发现分配代码本身有任何区别。 - Arnaud Bouchez
@DavidHeffernan 确实听起来像是一个 Heisenbug。从 OP 的问题中可以看出,有一些间接的过程可以重现错误(比如 Paint GDI 消息处理)。延迟也可能是 Heisenbugs 的一个因素,特别是与消息处理相结合时。 - Arnaud Bouchez

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