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