我们在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(启动FastMM的初始实例并与主应用程序共享)的行为将导致问题,即使我没有调用该dll。接下来我要做的是修改主应用程序以启用动态加载该dll(从而强制将内存管理器安装到主应用程序中),看看是否会产生影响。
更新3:动态加载dll与不加载它的效果相同......一切正常。
答案 0 :(得分: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不赞成使用共享方法(以节省一些代码字节?)。