FastMM内存管理器在使用多线程情况下需要注意的问题。

本文深入探讨了在使用FastMM内存管理器的多线程环境下,如何避免内存访问错误及内存泄漏问题。通过分析FastMM内存管理器在多线程环境下的工作原理,解释了为何在使用API函数CreateThread创建线程时容易出现内存访问错误,并介绍了如何解决此问题。同时,提供了在线程中使用FastMM管理内存后遇到的内存泄漏问题的解决方案。

        FastMM内存管理器在使用多线程情况下需要注意的问题。

问题1:

  注:如果你在Delphi中,只是用TThread类创建线程,不会用到API函数CreateThread创建线程,哪么下面这篇文章你可以完全忽视。。  
  当然,如果你耐心的看完了下面这篇文章,你也会明白一些原来我们习惯使用,但FastMM或Delphi默认的内存管理器在背后默默的为你处理复杂的内存管理问题中的一些技术细节。
  FastMM内存管理器在内存管理方面的高效、稳定大家是有目共睹的,这个方面大家在网上随便一搜,就可以找到很多FastMM的性能测试报告,我就不多啰嗦了。
  如果你在使用FastMM的环境下,创建了多个线程(Worker或UI线程),这个又分为2种情况:
1.使用TThread类创建线程。这种方式创建的线程在FastMM环境下运行完全没有问题;
2.使用纯API函数CreateThread创建线程,这种情况下,例如不做特殊处理,程序会频繁的出现内存访问错误。
  现在就来讨论一下在使用FastMM的环境下使用纯API函数CreateThread创建线程,频繁出现内存访问错误的问题。
  问题的描述:因为我需要建立一个带自建消息循环的线程,以便使该线程能够响应其它线程发送的消息,所以我只有使用API函数CreateThread创建线程,并且在线程中使用了Tlist和String。这样,运行程序后,程序频繁的出现了内存访问错误。多线程情况下,问题就是复杂,开始我以为是Tlist和String数据线程同步的问题,当使用了临界区和互斥的情况下,仍然频繁发生内存访问错误。没办法,我只有将项目中use FastMM4去掉,使用Delphi默认的内存管理器,但是问题依旧出现,这时候我想起了exe和dll共享内存时,要加入ShareMem,我就试着加上了ShareMem,再运行程序,结果,程序运行了一天也没有发生任何错误。
  我当时就在想,虽然加入ShareMem,“解决”了上面这个问题,但ShareMem是为了解决exe和dll共享内存时产生的问题,而我里只是用了一个exe,并没有用到dll,这是怎么回事?查看ShareMem相关资料,发现一个重要的环境变量IsMultiThread,它指明系统是否运行在多线程环境下,如果该全局变量为True,哪么在多线程环境下,内存的分配和释放都要用“临界区”进行同步以保证安全。而我在线程中用到了String,它正是在线程中动态的分配和释放了内存,所以引起了冲突。
  知道了问题所在,在FastMM使用在多线程的环境下,FastMM管理器在线程中分配和释放内存的时候也是要判断环境变量IsMultiThread,也是要同步以保证安全。当然FastMM和Delphi默认的内存管理器在这点上使用的同步方法略有差异,一个是使用临界区同步,另一个是使用CPU指令锁定同步,当然对用户来说,结果是一样的,哪就是在多线程的环境下,内存的分配和释放一定要同步保护。
  好了,现在在使用FastMM时,只要手动将IsMultiThread设为True,上面的错误就不会发生了,事实也证明了这一点,重新改过后,使用FastMM在多线程环境下就再也没有出现问题了,效率还大幅提高(相对于Delphi默认的内存管理器)。
  本来,问题已经解决完了,但我这人偏偏是一个喜欢刨根问底的人,因为我想到了原来我在FastMM下使用TThread类创建线程,并没有手动设置IsMultiThread环境变量,但也一直没有出现问题,这是为什么?
  原来,TThread类内部在Create时调用了BeginThread()函数,而BeginThread()函数是这样实现的:
  New(P);
  P.Func := ThreadFunc;
  P.Parameter := Parameter;
  IsMultiThread := TRUE;
  Result := CreateThread(SecurityAttributes, StackSize, @ThreadWrapper, P,
    CreationFlags, ThreadID);

    看见了吗?里面已经将IsMultiThread := TRUE; 所以这样就不会出现问题了。

  原来如此啊,隐藏的好深啊。。。。。

问题2:在线程中使用FastMM管理内存后的内存泄漏问题。
  本来,这种情况一般情况下不是FastMM问题,但情况总有可能出现二般的情况。比如,你在线程的Execute()中动态创建了几个对象,甚至可能创建了接口对象(IInterface或IUnknown),你也记着在线程结束的时候销毁这些对象了,但程序运行后,有时候会发生少量的内存泄漏问题,一般情况下是对象,接口或者字符串这些资源。当然,大多数情况下,这种问题不会发生,比如你的程序比较小,只有几千行代码,哪是不会有问题的,要是你的程序比较大,有个七八万或十几万行。哪么,不注意的话,FastMM在线程中的内存泄漏问题会经常出现,搞的人很郁闷。。
  其实,解决起来也很简单,在线程最后退出的的代码中在对象Free后,加入sleep(100)或者sleep(xxx)就可以解决这个问题了,sleep(xxx)中的xxx是视你的程序的实际情况增加的延时,我这里测试,加入50毫秒以上的延时,基本上就不会出现内存泄漏问题了。加入sleep(xxx)的作用主要是让FastMM有时间清理对象释放后占用的内存。就是这么简单,但这是我痛苦了一个星期后才懂的道理。。现在你看到了这篇文章,就不用像我哪样痛苦一个星期了。。。。。

FastMM5 FastMM 是 Embarcadero Delphi 应用程序的快速替换内存管理器,它可以跨多个线程和 CPU 内核很好地扩展,不易出现内存碎片,并支持共享内存而无需使用外部 .DLL 文件。 FastMM5-social.png 版本 5FastMM 的完全重写。它是从头开始设计的,旨在同时保持 4.992 版的优势并解决其缺点: 跨多个 CPU 内核的多线程扩展得到了大幅改进,而不会出现内存使用量激增。它可以配置为针对任意数量的 CPU 内核进行近乎线性的扩展。 在 Fastcode 内存管理器基准测试工具中,FastMM 5 在单线程基准测试中的得分比 FastMM 4.992 高 15%,在多线程基准测试中高 30%。(I7-8700K CPU,启用 EnableMMX 和 AssumeMultithreaded 选项。 它是完全可配置的运行时。无需更改条件定义并重新编译即可更改选项。(但是,它与许多版本 4 条件定义向后兼容。 默认情况下,Debug 模式使用与版本 4 (FastMM_FullDebugMode.dll) 相同的调试支持库,但也支持自定义堆栈跟踪例程。调用 FastMM_EnterDebugMode 切换到调试模式 (“FullDebugMode”),调用 FastMM_ExitDebugMode 返回性能模式。调用可能是嵌套的,在这种情况下,调试模式将在最后一次 FastMM_ExitDebugMode 调用后退出。 支持所有块的 8、16、32 或 64 字节对齐。调用 FastMM_EnterMinimumAddressAlignment 请求最小块对齐,FastMM_ExitMinimumAddressAlignment 撤销之前的请求。调用可能是嵌套的,在这种情况下,最粗略的对齐请求将生效。 所有事件通知(
上次在盒子上用了可以加快Delphi2005速度的FastMM后,经试用,效果确实不错,于是我便在找一下FastMM在其它方面的应用。地址:http://sourceforge.net/projects/fastmm发现这个FastMM同样可以使Delphi以及用Delphi开发的程序变得更快(包括C++ Build 6)使用方法:解开FastMM427.zip,找到里面的FastMm427Replacement BorlndMM DLLPrecompiledfor Delphi IDEPerformance目录下的borlndMM.dll文件,把它复制到Delphi安装目录的bin中,把原文件覆盖即可。在应用程序中的使用,作者是这样说的:Using FastMM is very simple. All you have to do is add FastMM.pas as the very first unit in your project's .dpr file. Note that if you application uses .DLL files and you will be sharing memory (i.e. passing long strings or dynamic arrays between the DLL and main application), that you have to use FastMM in the DLL as well. If FastMM is not the first file in the "uses" section of the .dpr file, you will get an "invalid pointer operation" during program startup (meaning the default MM has already been used to allocate some memory). 意思是您只需要把FastMM4.pas加入到你的项目中,但要保证dpr文件uses后面第一个文件就是FastMM4.pas即可,经过本人实验,实际使用中还要加FastMM4Messages.pas或者设置一个搜索路径(设路径比较麻烦,还是加进来吧)。然后编译你的程序就可以了。如果你的dll用了共享内存,那么就用FastMM427Replacement BorlndMM DLLPrecompiledfor ApplicationsPerformance中的BorlndMM.dll和你的DLL文件一起分发即可。因为没看到盒子上有这方面的东西,因此就上传一个了。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值