Delphi7 中使用FastMM

Delphi7 中使用FastMM
在工程的第一行引用FastMM4即可(注意,一定要在第一个Uses的位置),可以在调试程序时提示内存泄露情况,还可以生成报告。
在Delphi2007以后版本中,使用更加简单,只需要在工程开始的位置加上语句:
ReportMemoryLeaksOnShutdown := True;就可以了,并且在运行时不会出现提示。如果想要生成文件报告,还需要FastMM4,Delphi中没有别的设置可以生成文件报告。
可以修改FastMM4Options.inc中的参数开关来修改内存管理的相关设置。

 

 

具体项目中配置:

project -->Options 窗口中:

Linker Tab页中Map file 选择 Detailed 。

Compiler Tab页中 Debugging 中把 Use Debug DCUs 选择打钩。


1>  FastMM是开源项目, 从 http://sourceforge.net/projects/fastmm 下载最新版
2>  文件夹Replacement BorlndMM DLL/Precompiled/for Delphi IDE/Performance/BorlndMM.dll,替换掉Delphi/Bin下的相应文件就可以完成对IDE的提速
3> Enviroment->Library->Directories-> Library Path 添加FassMM路径,我放在Delphi安装目录下,直接设置为$(DELPHI)/FastMM
4> 在你的项目文件中,Project->View Source打开后,uses 后第一个添加FastMM4单元
5> 编译运行你的程序,如果有Memory leak,在关闭程序时会有一个提示对话框.

首先在自己的project里把FastMM4放在最前面,例如:  
FastMM4,  
Main   in   ‘Main.pas’   {MainForm},  
再修改FastMM4Options.inc,打开全调试模式。例:  
{$define   FullDebugMode}  
也可以在project中定义编译常量:FullDebugMode。
同时把FastMM_FullDebugMode.dll拷贝到编译后生成的可执行程序所在目录。
再要打开内存泄漏报告:EnableMemoryLeakReporting。一般情况下是缺省打开的。  这样就打开了全调试模式,如果发生内存泄漏将会生成报告文件,如果在IDE运行的时候还会弹出一个对话框显示。报告文件类似:XXX_MemoryManager_EventLog.txt 


如果下载的FastMM4Options.inc 不能生成 日志文件即: 项目名_ _MemoryManager_EventLog.txt文件(在项目Exe输出目录中),则需要把一下内容覆盖掉原来的FastMM4Options.inc文件。

FastMM最新版本提供了中文语言包,可方便国内使用。下载地址为
http://sourceforge.net/projects/fastmm/
配置文件为:FastMM4Options.inc,
中文详细配置方法如下:
 /
 {
Fast Memory Manager: 选项配置文件
在这里为FastMM设置默认选项
FastMM 4.84
}
{
   Simplified Chinese translation by QianYuan Wang
   Contact me if you find any improper translation.
   如果翻译上有任何不恰当的地方请和我联系。
   E-Mail:
wqyfavor@163.com
}
{
 对各编译选项的翻译(不解释术语)
 
 Align16Bytes      按16字节对齐
 UseCustomFixedSizeMoveRoutines   使用固定尺寸内存移动函数
 UseCustomVariableSizeMoveRoutines   使用可变尺寸内存移动函数
 AssumeMultiThreaded     按多线程处理
 NeverSleepOnThreadContention    线程冲突时不暂停进程
 InstallOnlyIfRunningInIDE    仅在Delphi开发环境中加载内存管理器
 NeverUninstall     不卸载FastMM
 UseRuntimePackages     使用运行期包
 
 NoDebugInfo      无调试信息
 NoMessageBoxes     不显示信息
 UseOutputDebugString     使用Windows API OutputDebugString
 ASMVersion      汇编版本
 CheckHeapForCorruption    检测堆错误
 DetectMMOperationsAfterUninstall   检测在管理器卸载后对其的引用操作
 FullDebugMode      全调试模式
   RawStackTraces     彻底的栈追踪
   CatchUseOfFreedInterfaces    捕捉对已销毁对象的引用
   LogErrorsToFile     记录错误到文件
   LogMemoryLeakDetailToFile    记录内存泄露细节到文件
   ClearLogFileOnStartup    启动时清空日志文件
   LoadDebugDLLDynamically    动态加载调试Dll
   AlwaysAllocateTopDown    总从最顶端分配内存
 EnableMemoryLeakReporting    允许内存泄露报告
   HideExpectedLeaksRegisteredByPointer  隐藏由指针记录的可能的内存泄露
   RequireIDEPresenceForLeakReporting   仅在IDE存在时进行泄露报告
   RequireDebuggerPresenceForLeakReporting  仅在调试器存在时进行泄露报告
   RequireDebugInfoForLeakReporting   泄露报告需要调试信息
   ManualLeakReportingControl    手工控制泄露报告
   HideMemoryLeakHintMessage    隐藏内存泄露提示信息
 EnableMMX      允许使用MMX
   ForceMMX      强制使用MMX
 ShareMM      共享内存管理器
   ShareMMIfLibrary     允许在Dll中共享内存管理器
 AttemptToUseSharedMM     尝试共享内存管理器
 EnableBackwardCompatibleMMSharing   允许向后兼容的内存管理器共享
 FullDebugModeInIDE     在Delphi开发环境中进行全调试
}
{--------------------------- 综合选项 -----------------------------}
{开启此选项会将所有内存块按16字节对齐以便SSE指令可以安全使用。如果此选项关闭,一些
 最小的内存块会按8字节方式对齐,这将减少内存使用。不管是否开启此选项,中等和大的内
 存块都将按照16字节方式对齐。}
{.$define Align16Bytes}
{允许在增大小内存块时使用更快的定尺寸内存移动函数。因为这些函数被设计为移动固定尺寸
 内存,所以效率大幅高于Borland的RTL中的内存移动函数。这一选项可与FastMove库配合使用
 来达到更高的效率。}
{$define UseCustomFixedSizeMoveRoutines}
{开启此选项以使用优化的函数来移动任意大小的内存块。使用Fastcode的FastMove函数时禁用
 此选项。使用FastMove代码可以使整个程序都使用到更快的内存移动函数而不仅仅是内存管理
 器。因此建议将FastMM和FastMove代码相结合,并关闭此选项。}
{$define UseCustomVariableSizeMoveRoutines}
{开启后将默认程序是多线程的,但会导致单线程程序速度明显下降。在使用可能未正确设
 置IsMultiThread变量的多线程的第三方工具时请开启此选项。在单线程主程序和多线程Dll
 间共享内存管理器时也需开启。}
{.$define AssumeMultiThreaded}
{开启此选项将不会在线程冲突时让一个线程暂停,在活动进程与CPU核心数目比低(小于2)时
 将会提升速度。开启后,冲突时一个线程将会进入“等待”循环而不是交出时间片。}
{.$define NeverSleepOnThreadContention}
{开启此选项会使程序仅在Delphi IDE内运行时才加裁FastMM作为内存管理器。当你希望发布的
 Exe就是你调试的Exe,但只希望在开发主机上使用调试时请开启此选项。当开启后程序又并不
 在开发主机上运行,它会使用默认的Delphi内存管理器(在Delphi2006以后是不开启FullDebugMode
 的FastMM)}
{.$InstallOnlyIfRunningInIDE}
{由于QC#14070(Delphi尝试在borlandmm.dll的关闭指令执行后释放内存),当使用了FastMM
 为核心的borlandmm.dll的替代品,FastMM不能被正常卸载。开启此选项会不卸载内存管理器
 而避开这个错误。}
{.$define NeverUninstall}
{如果在当前工程中使用了运行期的包,需要启动这个选项。会自动开启AssumeMultiThreaded。
 注意你必须确保在所有指针都释放后FastMM被卸载。如果不这么做会产生一个有很多A/V的巨
 大的内存泄露报告。(参考常见问题)你必须同时启动此选项和NeverUninstall选项。}
{.$define UseRuntimePackages}
{----------------------------- 调试选项 -------------------------------}
{开启此选项将不会为FastMM4.pas单元产生调试代码,也将同时阻止调试器进入FastMM4.pas单元}
{.$define NoDebugInfo}
{开启下面选项将不显示任何信息,在不可中止的服务器程序中比较有用}
{.$define NoMessageBoxes}
{如果要使用Windows API OutputDebugString过程来显示调试信息请开启下面选项}
{.$define UseOutputDebugString}
{开启此选项会使用汇编语言版本的FastMM,这比Pascal版本的要快。仅在调试时关闭此选项。
 开启CheckHeapForCorruption会自动关闭此设置}
{$define ASMVersion}
{FastMM总会捕捉到两次释放的同一内存区域的糟糕操作,它也可以检测堆的错误(通常是由
于程序越界读写内存)。这些检测很耗费时间,所以这个选项应仅当调试时使用。如果此选项
开启,ASMVersion会自动关闭}
{.$define CheckHeapForCorruption}
{开启此选项会检测在FastMM已卸载后对用户对FastMM的引用操作。开启后,当FastMM被卸载,
 将不会重新启动先前的内存管理器,而是假想存在一个内存管理器,并且一旦有内存操作便
 抛出错误。这会捕捉到当FastMM已被卸载而程序仍进行内存操作的错误。}
{$define DetectMMOperationsAfterUninstall}
{设置以下选项来对内存泄露进行广泛检测。所有内存块都会设置块首和跟踪器来校验堆的完
 整性。释放的内存块(指针)也会被清空以保证它们不会被再次使用。这一选项会大幅度降
 低内存操作速度,仅当调试一个会越界读写内存或重复使用已被释放的指针的程序时才使用。
 开启此选项会进而自动开启CheckHeapForCorruption并自动关闭ASMVersion。提示:当开启
 此选项时,程序需要使用FastMM_FullDebugMode.dll文件。如果此文件丢失,程序将无法启动。}
{$define FullDebugMode}
  {开启此选项以进行彻底的栈追踪:检测所有栈条目以寻找合法的返回地址。注意这比使用
   主栈帧的方法要慢很多,但更彻底。仅当开启FullDebugMode时此选项有效。}
  {$define RawStackTraces}
  {开启此选项会检测程序中对已销毁对象的引用。注意这会使对已释放而又修改过(内容被
   覆盖)的内存块的检测无法进行(两者无法共存)。仅当开启FullDebugMode时此选项有效。}
  {.$define CatchUseOfFreedInterfaces}
  {开启此选项以记录所有的错误到一个与程序同目录的文本文件中。内存分配错误(当开启
   FullDebugMode)将会添加到这个日志里。如果FullDebugMode关闭,此选项无效}
  {$define LogErrorsToFile}
  {开启此选项将会记录所有泄露到一个与程序同目录的文本文件中。内存泄露报告(当开启
   FullDebugMode)将会添加到这个日志里。如果"LogErrorsToFile"和"FullDebugMode"未开
   启此选项无效。注意通常所有泄露都会被记录,甚至那些AddExpectedMemoryLeaks标识的
   可能的内存泄露。那些由指针引起的可能的泄露可能会由于开启HideExpectedLeaks-
   RegisteredByPointer而不显示。}
  {$define LogMemoryLeakDetailToFile}
  {程序启动时删除日志文件。当LogErrorsToFile不开启时无效}
  {.$define ClearLogFileOnStartup}
  {是否动态链接FASTMM_FullDebugMode.dll。如果找不到该Dll,栈追踪将无法进行。注意
   当共享内存管理器时由于Dll卸载顺序改变,可能会发生错误。}
  {.$define LoadDebugDLLDynamically}
  {FastMM通常会使用最顶端的可用地址来分配大的内存块,而在最低端的可用地址上分配
   中、小内存块(这在一定程度上减少碎片)。开启此选项会使内存分配总优先使用最顶
   端的可用地址。如果过程使用了大于2GB的内存并且算法存在糟糕的指针分配 ,这个选
   项会帮助尽早发现错误}
  {$define AlwaysAllocateTopDown}
{--------------------------- 内存泄露报告 -----------------------------}
{开启此选项以允许内存泄露报告,与下面两个选项组合使用。}
{$define EnableMemoryLeakReporting}
  {开启下面选项将不会显示和记录由指针类型导致的可能的内存泄露。由类(指针)引起
   的可能的内存泄露经常不明确,所以这些可能的泄露总是会记录到日志(在FullDebugMode
   与LogMemoryLeakDetailToFile开启时)并且当实际泄露比期待的多时一定会显示。}
  {$define HideExpectedLeaksRegisteredByPointer}
  {开启下面选项以实现仅在Delphi在主机上存在时才报告内存泄露。当"EnableMemoryLeakReporting"
   关闭时此选项无效。}
  {.$define RequireIDEPresenceForLeakReporting}
  {开启下面选项以实现仅在Delphi中调试程序时才报告内存泄露。当"EnableMemoryLeakReporting"
   关闭时此选项无效。此选项仅在调试EXE工程时有效,不支持Dll}
  {$define RequireDebuggerPresenceForLeakReporting}
  {开启下面选项以实现仅在被编译单元中存在调试指示符($D)时才进行泄露检测。当
   "EnableMemoryLeakReporting"关闭时此选项无效。}
  {.$define RequireDebugInfoForLeakReporting}
  {开启此选项以手工控制内存泄露报告。当开启时,ReportMemoryLeaksOnShutdown(程序
   关闭时报告内存泄露,默认关闭)会改为选择是否生成报告。开启时,其它泄露检测选项
   也必须正确设置才能进行检测}
  {.$define ManualLeakReportingControl}
  {开启下面选项将不显示内存泄露信息下面的提示语}
  {.$define HideMemoryLeakHintMessage}
{-------------------------- 指令集设置 ----------------------------}
{开启下面选项以使用MMX指令集。关闭此选项会导致性能略微下降,但会与AMD K5、
 Pentium I等早期处理器保持兼容。目前MMX指令只在可变尺寸的内存移动中使用,所以如
 果UseCustomVariableSizeMoveRoutines关闭,此选项无效。}
{.$define EnableMMX}
  {开启下面选项以强制使用MMX指令集,而不管CPU是否支持。如果这一选项被关闭,
   将会首先检查CPU是否支持MMX指令。当EnabledMMX关闭时无效。}
  {$define ForceMMX}
{----------------------- 共享内存管理器设置 ------------------------}
{允许共同使用FastMM编译的主程序和Dll之间共享内存管理器。你可以向Dll中的函数传递
 动态数组和长字符串。需要编译Dll时开启AttemptToUseSharedMM才可以真正实现内存共享。
 注意如果主程序是单线程而Dll是多线程的,你必须在主程序里开启IsMultiThread,否则在
 线程冲突时程序会崩溃。注意静态链接的Dll会在主程序之前初始化,所以主程序实际会与
 Dll共享内存管理器。
}
{.$define ShareMM}
  {允许Dll之间(或静态链接Dll时与主程序之间)共享内存管理器,要求共同使用FastMM编译。
   在使用动态链接的Dll时需要注意,因为如果Dll被卸载而其它Dll仍在共享内存管理器,程
   序将会崩溃。这个选项只与Dll库相关而且需要ShareMM与AttemptToUseSharedMM开启。注意
   如果Dll是静态链接的,它们会在主程序之前初始化,实际是主程序与它们共享管理器。当
   ShareMM关闭时此选项无效}
  {.$define ShareMMIfLibrary}
{开启下面选项,会尝试在主程序和与之共同编译的Dll(也开启此选项)之间共享内存管理
 器。当共享时,由使用共享者产生的泄露将不会自动清除。由于静态链接的Dll是在主程序
 之前初始化的,所以根据情况设置共享选项}
{.$define AttemptToUseSharedMM}
{开启下面编译选项以保证内存管理器的向后兼容性。对Delphi2006与Delphi2007与老版本
FastMM有效}
{$define EnableBackwardCompatibleMMSharing}
{-------------------------------- 组合设置 ------------------------------}
{开启此选项将激活FullDebugMode、InstallOnlyIfRunningInIDE、LoadDebugDLLDynamically。
 如果程序正在Delphi中进行调试运行,FastMM将会进行完全调试(开启FullDebugMode),否则
 将使用默认内存管理器(Delphi2006版本以后是未开启FullDebugMode的FastMM)。}
{.$define FullDebugModeInIDE}
{快速配置发布版本和调试版本}
{$ifdef Release}
  {发布版本请设置}
  {.$undef FullDebugMode}
  {.$undef CheckHeapForCorruption}
  {.$define ASMVersion}
  {.$undef EnableMemoryLeakReporting}
  {.$undef UseOutputDebugString}
{$else}
  {高度版本请设置}
  {.$define FullDebugMode}
  {.$define EnableMemoryLeakReporting}
  {.$define UseOutputDebugString}
{$endif}
{-------------------- borlndmm.dll 编译选项 ---------------------}
{如果正在重编译borlandmm.dll文件,请根据需要设置以下选项}
{当编译borlandmm.dll时请开启此选项}
{.$define borlndmmdll}
{如果dll被Delphi本身使用请开启此选项}
{.$define dllforide}
{编译调试dll文件时请开启此选项}
{.$define debugdll}
{以下内容请不要改动}
{$ifdef borlndmmdll}
  {$define AssumeMultiThreaded}
  {$undef HideExpectedLeaksRegisteredByPointer}
  {$undef RequireDebuggerPresenceForLeakReporting}
  {$undef RequireDebugInfoForLeakReporting}
  {$define DetectMMOperationsAfterUninstall}
  {$undef ManualLeakReportingControl}
  {$undef ShareMM}
  {$undef AttemptToUseSharedMM}
  {$ifdef dllforide}
    {$define NeverUninstall}
    {$define HideMemoryLeakHintMessage}
    {$undef RequireIDEPresenceForLeakReporting}
    {$ifndef debugdll}
      {$undef EnableMemoryLeakReporting}
    {$endif}
  {$else}
    {$define EnableMemoryLeakReporting}
    {$undef NeverUninstall}
    {$undef HideMemoryLeakHintMessage}
    {$define RequireIDEPresenceForLeakReporting}
  {$endif}
  {$ifdef debugdll}
    {$define FullDebugMode}
    {$define RawStackTraces}
    {$undef CatchUseOfFreedInterfaces}
    {$define LogErrorsToFile}
    {$define LogMemoryLeakDetailToFile}
    {$undef ClearLogFileOnStartup}
  {$else}
    {$undef FullDebugMode}
  {$endif}
{$endif}
{把BCB的相关设置都放在这里。在“Build with Dynamic RTL”选项开启的情况下,
CB2006/CB2007可以编译borlandmm.dll文件以追踪内存泄露。}
{------------------------------ 专为BCB设置 ----------------------------}
{要开启为BCB准备的补丁,你需要在"Project Options->Pascal/Delphi Compiler->Defines"
 中添加BCB的定义。(感谢JiYuan Xie实现这一部分)}
{$ifdef BCB}
  {$ifdef CheckHeapForCorruption}
    {$define PatchBCBTerminate}
  {$else}
    {$ifdef DetectMMOperationsAfterUninstall}
      {$define PatchBCBTerminate}
    {$else}
       {$ifdef EnableMemoryLeakReporting}
         {$define PatchBCBTerminate}
       {$endif}
    {$endif}
  {$endif}
  {$ifdef PatchBCBTerminate}
    {$define CheckCppObjectType}
    {$undef CheckCppObjectTypeEnabled}
    {$ifdef CheckCppObjectType}
      {$define CheckCppObjectTypeEnabled}
    {$endif}
    {如果"CheckHeapForCorruption"和"EnableMemoryLeakReporting"都未开启,请关闭
     "CheckCppObjectTypeEnabled"}
    {$ifdef CheckHeapForCorruption}
    {$else}
      {$ifdef EnableMemoryLeakReporting}
      {$else}
        {$undef CheckCppObjectTypeEnabled}
      {$endif}
    {$endif}
  {$endif}
{$endif}

 

摘自:http://blog.csdn.net/shuaihj/article/details/6256873


/

 

问题:

A memory block has been leaked. The size is: 36

This block was allocated by thread 0x1378, and the stack trace (return addresses) at the time was:
402CC3 [pngzlib][pngzlib][@GetMem]
403967 [pngzlib][pngzlib][TObject.NewInstance]
403D36 [pngzlib][pngzlib][@ClassCreate]
438C66 [SyncObjs][SyncObjs][TCriticalSection.Create]
4045E3 [pngzlib][pngzlib][@InitResStringImports]
55F3D7 [IdComponent][IdComponent][IdComponent]
40453C [pngzlib][pngzlib][InitUnits]
4045A3 [pngzlib][pngzlib][@StartExe]
4070DB [SysInit][SysInit][@InitExe]
578266 [E:\delphiWorkspace\NPMPO\NPMPO.dpr][NPMPO][NPMPO][31]
74FC3677 [BaseThreadInitThunk]

The block is currently used for an object of class: TCriticalSection

The allocation number is: 326

-------------------------------
有关21 - 36 字节: TCriticalSection x 1内存泄露的问题:

所有 VCL 控件都有这个内存泄漏,这个是 VCL 控件故意之所为,这个不是 PHPRPC 的问题,相关资料

initialization
  GStackCriticalSection := TCriticalSection.Create;
finalization
  // Dont Free. If shutdown is from another Init section, it can cause GPF when stack
  // tries to access it. App will kill it off anyways, so just let it leak
  // FreeAndNil(GStackCriticalSection);

 -----------------------------

报告中未包含自己项目代码的,则忽略。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
关键字: 内存泄漏 checkMem.pas 摘要:   这是一篇介绍如何使用CheckMem.pas单元检查delphi应用程序内存泄漏的文章 作者:999roseto347(fdaf at 163 dot com) 版本:V1.0 创建日期:2004-06-11 目录: 一、使用步骤 二、报告解读 三、测试例子 四、内存泄漏测试及修复的技巧 附:CheckMem.pas单元 一、使用步骤: A)、将CheckMem.pas单元加入到工程 B)、修改工程文件,将'CheckMem.pas'放到uses下的第一句 program Project1; uses CheckMem in 'CheckMem.pas', Forms, Unit1 in 'Unit1.pas' {Form1} ;//其他单元文件 {$R *.RES} begin Application.Initialize; Application.CreateForm(TForm1, Form1); Application.Run; end. C)、正常的编译、运行应用程序 D)、退出应用程序后,将在应用程序目录下生成报告(如果有漏洞的话,如果没有则不生成)。 二、报告解读: 报告的内容: ===== Project1.exe,2004-6-11 15:36:55 ===== 可用地址空间 : 1024 KB(1048576 Byte) 未提交部分 : 1008 KB(1032192 Byte) 已提交部分 : 16 KB(16384 Byte) 空闲部分 : 13 KB(14020 Byte) 已分配部分 : 1 KB(2024 Byte) 全部小空闲内存块 : 0 KB(232 Byte) 全部大空闲内存块 : 11 KB(11864 Byte) 其它未用内存块 : 1 KB(1924 Byte) 内存管理器消耗 : 0 KB(340 Byte) 地址空间载入 : 0% 当前出现 3 处内存漏洞 : 0) 0000000000F33798 - 19($0013)字节 - 不是对象 1) 0000000000F337A8 - 18($0012)字节 - 不是对象 2) 0000000000F337B8 - 18($0012)字节 - 不是对象 解读如下: 当前出现 3 处内存漏洞 :(有三个内存块分配了,但未释放。注意这里不是指对象变量或指针变量的地址,是对象的内存区域或指针指向的内存地址) 序号 未释放内存的地址  内存大小    是否是对象?如果是列出对象的Name及class并指出对象实现的单元文件名 0) 0000000000F33798 - 19($0013)字节 - 不是对象 三、测试例子: 测试用的代码: unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; Button2: TButton; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); private { Private declarations } public { Public declarations } aa:TstringList; bb:tbutton; end; var Form1: TForm1; def:pointer; implementation {$R *.DFM} procedure TForm1.Button1Click(Sender: TObject); begin aa:=TstringList.Create; bb:=Tbutton.Create(nil); aa.Add('abcdefdafasdfasdfasdfasdf'); application.MessageBox(pchar(aa.Strings[0]),'asdf',MB_OK); // aa.Free; end; procedure TForm1.Button2Click(Sender: TObject); var p:Pointer; begin GetMem(def,10); p:=def; fillchar(p,10,$65); application.MessageBox (def,'aaa',MB_OK); // freemem(def,10); end; end. 我们先点击button1,然后退出。出现的报告如下: 当前出现 10 处内存漏洞 : 0) 0000000000F3109C - 67($0043)字节 - 不是对象 1) 0000000000F316A4 - 39($0027)字节 - 不是对象 2) 0000000000F33798 - 55($0037)字节 - (未命名): TStringList (48 字节) - In Classes.pas 3) 0000000000F337CC - 518($0206)字节 - : TButton (512 字节) - In StdCtrls.pas 4) 0000000000F339D0 - 42($002A)字节 - MS Sans Serif : TFont (36 字节) - In Graphics.pas 5) 0000000000F339F8 - 38($0026)字节 - (未命名): TSizeConstraints (32 字节) - In Controls.pas 6) 0000000000F33A1C - 30($001E)字节 - (未命名): TBrush (24 字节) - In Graphics.pas 7) 0000000000F33A38 - 38($0026)字节 - 不是对象 8) 0000000000F33A5C - 38($0026)字节 - 不是对象 9) 0000000000F33A80 - 42($002A)字节 - 不是对象 把bb:=Tbutton.Create(nil);注释掉://bb:=Tbutton.Create(nil);再重新编译,然后运行,再点button1。出现的报告如下: 当前出现 3 处内存漏洞 : 0) 0000000000F33798 - 55($0037)字节 - (未命名): TStringList (48 字节) - In Classes.pas 1) 0000000000F337CC - 38($0026)字节 - 不是对象 2) 0000000000F337F0 - 42($002A)字节 - 不是对象 说明了:一个对象未释放,将引起多处内存泄漏(因为一个对象可能包含多个子对象) OK,我们再来测试button2(注意,这次我们不点击button1,只点击button2 一次),产生的报告如下: 当前出现 1 处内存漏洞 : 0) 0000000000F33798 - 19($0013)字节 - 不是对象 再来一次,这次点击button2 三次: 当前出现 3 处内存漏洞 : 0) 0000000000F33798 - 19($0013)字节 - 不是对象 1) 0000000000F337A8 - 18($0012)字节 - 不是对象 2) 0000000000F337B8 - 18($0012)字节 - 不是对象 这说明:对于每一个未释放的内存,CheckMem都将记录下来!再注意上面的未释放内存的地址是紧挨着的,因此如果看到这样的报告,可以猜想为一变量,多次分配,但未释放! 四、内存泄漏测试及修复的技巧:(翻译自MemProof帮助的部分内容,翻译得不好,请大家来信指导) The following are a couple of tips that can be usefull when fixing leaks in an application : 下面的这些技巧对于修复应用程序的内存泄漏非常有用: * First just launch the app and then close it. If even this action generates leaks, fix those leaks first. Only after the main leaks are fixed, you should go into specific functionality areas of the application. *首先,运行应用程序然后马上退出。如果这样操作也产生内存泄漏,先修复这些漏洞。只有先修复这些主要的泄漏,你才能进行特定功能的测试。 * In your Delphi/C++Builder project options, remove as much forms as possible from the Auto-Create option. Create your forms dynamically. *在你的delphi/C++Builder工程选项,尽可能地不要使用自动创建窗体,你需要时再动态创建。 * 注意在循环创建或分配的内存的代码。如果它们未释放,可能引起大量的内存泄漏。 * Go for the biggest classes first - if you see a TMyFom <class> leaking, try to fix this one first instead of going after a tiny TFont class. Since a Form will usually contain a lot of other classes, with one shot you will have fixed a lot of contained leaks. *先修复大的类,比如你看到TMyFom 类有泄漏,先解决它的问题,然后再解决像TFont 这样的小类。一个form类经常包含多个子类。修复一个form的未释放问题,你将解决大量该form包含的子对象未释的问题。 * Go for the easy fixes first. Some leaks fixes are very easy and obvious - if you fix the easy ones first, you will keep them out of your way. *首先修复容易修复的漏洞。一些泄漏是非常容易被发现的,如果你先修复他们,你就不用老想着他们了。 附:CheckMem.pas单元 unit CheckMem; file://Add it to the first line of project uses interface procedure SnapCurrMemStatToFile(Filename: string); implementation uses Windows, SysUtils, TypInfo; const MaxCount = High(Word); var OldMemMgr: TMemoryManager; ObjList: array[0..MaxCount] of Pointer; FreeInList: Integer = 0; GetMemCount: Integer = 0; FreeMemCount: Integer = 0; ReallocMemCount: Integer = 0; procedure AddToList(P: Pointer); begin if FreeInList > High(ObjList) then begin MessageBox(0, '内存管理监视器指针列表溢出,请增大列表项数!', '内存管理监视器', mb_ok); Exit; end; ObjList[FreeInList] := P; Inc(FreeInList); end; procedure RemoveFromList(P: Pointer); var I: Integer; begin for I := 0 to FreeInList - 1 do if ObjList[I] = P then begin Dec(FreeInList); Move(ObjList[I + 1], ObjList[I], (FreeInList - I) * SizeOf(Pointer)); Exit; end; end; procedure SnapCurrMemStatToFile(Filename: string); const FIELD_WIDTH = 20; var OutFile: TextFile; I, CurrFree, BlockSize: Integer; HeapStatus: THeapStatus; Item: TObject; ptd: PTypeData; ppi: PPropInfo; procedure Output(Text: string; Value: integer); begin Writeln(OutFile, Text: FIELD_WIDTH, Value div 1024, ' KB(', Value, ' Byte)'); end; begin AssignFile(OutFile, Filename); try if FileExists(Filename) then begin Append(OutFile); Writeln(OutFile); end else Rewrite(OutFile); CurrFree := FreeInList; HeapStatus := GetHeapStatus; { 局部堆状态 } with HeapStatus do begin Writeln(OutFile, '===== ', ExtractFileName(ParamStr(0)), ',', DateTimeToStr(Now), ' ====='); Writeln(OutFile); Output('可用地址空间 : ', TotalAddrSpace); Output('未提交部分 : ', TotalUncommitted); Output('已提交部分 : ', TotalCommitted); Output('空闲部分 : ', TotalFree); Output('已分配部分 : ', TotalAllocated); Output('全部小空闲内存块 : ', FreeSmall); Output('全部大空闲内存块 : ', FreeBig); Output('其它未用内存块 : ', Unused); Output('内存管理器消耗 : ', Overhead); Writeln(OutFile, '地址空间载入 : ': FIELD_WIDTH, TotalAllocated div (TotalAddrSpace div 100), '%'); end; Writeln(OutFile); Writeln(OutFile, Format('当前出现 %d 处内存漏洞 :', [GetMemCount - FreeMemCount])); for I := 0 to CurrFree - 1 do begin Write(OutFile, I: 4, ') ', IntToHex(Cardinal(ObjList[I]), 16), ' - '); BlockSize := PDWORD(DWORD(ObjList[I]) - 4)^; Write(OutFile, BlockSize: 4, '($' + IntToHex(BlockSize, 4) + ')字节', ' - '); try Item := TObject(ObjList[I]); if PTypeInfo(Item.ClassInfo).Kind <> tkClass then { type info technique } write(OutFile, '不是对象') else begin ptd := GetTypeData(PTypeInfo(Item.ClassInfo)); ppi := GetPropInfo(PTypeInfo(Item.ClassInfo), 'Name'); { 如果是TComponent } if ppi <> nil then begin write(OutFile, GetStrProp(Item, ppi)); write(OutFile, ' : '); end else write(OutFile, '(未命名): '); Write(OutFile, Item.ClassName, ' (', ptd.ClassType.InstanceSize, ' 字节) - In ', ptd.UnitName, '.pas'); end except on Exception do write(OutFile, '不是对象'); end; writeln(OutFile); end; finally CloseFile(OutFile); end; end; function NewGetMem(Size: Integer): Pointer; begin Inc(GetMemCount); Result := OldMemMgr.GetMem(Size); AddToList(Result); end; function NewFreeMem(P: Pointer): Integer; begin Inc(FreeMemCount); Result := OldMemMgr.FreeMem(P); RemoveFromList(P); end; function NewReallocMem(P: Pointer; Size: Integer): Pointer; begin Inc(ReallocMemCount); Result := OldMemMgr.ReallocMem(P, Size); RemoveFromList(P); AddToList(Result); end; const NewMemMgr: TMemoryManager = ( GetMem: NewGetMem; FreeMem: NewFreeMem; ReallocMem: NewReallocMem); initialization GetMemoryManager(OldMemMgr); SetMemoryManager(NewMemMgr); finalization SetMemoryManager(OldMemMgr); if (GetMemCount - FreeMemCount) <> 0 then SnapCurrMemStatToFile(ExtractFileDir(ParamStr(0)) + '\CheckMemory.Log');
安装 Delphi 11 FastMM 是一个相对简单的过程。FastMM 是一款强大的内存管理工具,可以帮助我们在开发过程更好地管理和优化内存使用。 以下是安装 FastMM 的步骤: 1. 首先,下载 FastMM 的安装文件。可以在 FastMM 的官方网站或其他可信的下载网站上找到它。确保下载适用于 Delphi 11 的版本。 2. 下载完成后,解压安装文件,并打开解压后的文件夹。该文件夹应该包含 FastMM 的源代码和一些其他相关文件。 3. 打开 Delphi 11。在“工具”菜单,选择“导入工具”或“安装组件”选项。 4. 在弹出的对话框,点击“添加”按钮,并选择 FastMM 的源代码文件(通常为 FastMM4.pas)。 5. 然后,点击“打开”按钮,返回到安装对话框。 6. 在安装对话框,可以选择编译成静态库或动态库的方式。这里我们选择编译成动态库(DLL)的方式,方便以后在其他项目共享。 7. 点击“编译”按钮开始编译。 8. 编译完成后,点击“安装”按钮进行安装。安装完成后,可以关闭安装对话框。 9. 现在,FastMM 已经安装在 Delphi 11 了,可以在开发过程使用它来进行内存管理。 安装完成后,我们可以在 Delphi 11 的项目使用 FastMM。为了使用它,只需在项目文件的使用部分添加 FastMM 单元即可。例如,在项目文件的 interface 部分添加“uses FastMM4;”语句。 总体而言,安装 Delphi 11 FastMM 相对简单。通过按照上述步骤,我们可以很容易地将其集成到我们的开发环境,并利用其强大的内存管理功能优化我们的程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值