FastMMMemLeakMonitor.pas
上传用户:yjb1804
上传日期:2021-01-30
资源大小:3105k
文件大小:10k
源码类别:

Email服务器

开发平台:

Delphi

  1. {#(@)$Id: FastMMMemLeakMonitor.pas,v 1.1 2006/07/19 02:55:29 judc Exp $ }
  2. {  DUnit: An XTreme testing framework for Delphi programs. }
  3. (*
  4.  * The contents of this file are subject to the Mozilla Public
  5.  * License Version 1.1 (the "License"); you may not use this file
  6.  * except in compliance with the License. You may obtain a copy of
  7.  * the License at http://www.mozilla.org/MPL/
  8.  *
  9.  * Software distributed under the License is distributed on an "AS
  10.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  11.  * implied. See the License for the specific language governing
  12.  * rights and limitations under the License.
  13.  *
  14.  * The Original Code is DUnit.
  15.  *
  16.  * The Initial Developers of the Original Code are Kent Beck, Erich Gamma,
  17.  * and Juancarlo A馿z.
  18.  * Portions created The Initial Developers are Copyright (C) 1999-2000.
  19.  * Portions created by The DUnit Group are Copyright (C) 2000-2004.
  20.  * All rights reserved.
  21.  *
  22.  * Contributor(s):
  23.  * Kent Beck <kentbeck@csi.com>
  24.  * Erich Gamma <Erich_Gamma@oti.com>
  25.  * Juanco A馿z <juanco@users.sourceforge.net>
  26.  * Chris Morris <chrismo@users.sourceforge.net>
  27.  * Jeff Moore <JeffMoore@users.sourceforge.net>
  28.  * Uberto Barbini <uberto@usa.net>
  29.  * Brett Shearer <BrettShearer@users.sourceforge.net>
  30.  * Kris Golko <neuromancer@users.sourceforge.net>
  31.  * The DUnit group at SourceForge <http://dunit.sourceforge.net>
  32.  * Peter McNab <>
  33.  *
  34.  *******************************************************************************
  35.  * Code to provide Memory Leak Detection at the test case level.
  36.  * This code makes use of FastMM4.pas available from
  37.  * http://fastmm.sourceforge.net
  38.  *
  39.  * FastMM is a fast replacement memory manager for Borland Delphi Win32
  40.  * applications that scales well under multi-threaded usage, is not prone to
  41.  * memory fragmentation, and supports shared memory without the use of
  42.  * external .DLL files.
  43.  * To use FastMM in DUnit for memory leak detection it is necessary to download
  44.  * the latest stable release of FastMM from "fastmm.sourceforge.net"
  45.  * Then add the path of the folder containing the FastMM4 source code to the
  46.  * DUnit project's search path.
  47.  *
  48.  * Generally it should not be necessary to change FastMMOptions.inc settings.
  49.  * However read the notes in FastMMOptions.inc carefully to understand the
  50.  * effect of each option and set accordingly to best meet your testing
  51.  * environment.
  52.  *
  53.  * Finally, select
  54.  *   "Project, Option, Directories/Conditionals, Conditional Defines"
  55.  * in the Delphi IDE and add the conditional define
  56.  *   FASTMM (prefix with an extra ; if there are other defines)
  57.  * to allow DUnit to use the FASTMM specific code.
  58.  *
  59. *)
  60. unit FastMMMemLeakMonitor;
  61. interface
  62. uses
  63. {$IFDEF VER180}
  64.   SysUtils,
  65. {$ELSE}
  66.   {$IFDEF FASTMM}
  67.     FastMM4,
  68.   {$ENDIF}
  69. {$ENDIF}
  70.   TestFrameWork;
  71. type
  72.   TMemLeakMonitor = class(TInterfacedObject, IMemLeakMonitor)
  73.   protected
  74.     FMS1: TMemoryManagerState;
  75.     FMS2: TMemoryManagerState;
  76.     function MemLeakDetected(out LeakSize: Integer): boolean; overload;
  77.   public
  78.     constructor Create;
  79.   end;
  80.   TDUnitMemLeakMonitor = class(TMemLeakMonitor, IDUnitMemLeakMonitor)
  81.     procedure MarkMemInUse;
  82.     function MemLeakDetected(const AllowedLeakSize: Integer;
  83.                              const FailOnMemoryRecovery: boolean;
  84.                              out   LeakSize: Integer): boolean; overload;
  85.     function MemLeakDetected(const AllowedValuesGetter: TListIterator;
  86.                              const FailOnMemoryRecovery: Boolean;
  87.                              out   LeakIndex: integer;
  88.                              out   LeakSize: Integer): Boolean; overload;
  89.     function GetMemoryUseMsg(const FailOnMemoryRecovery: boolean;
  90.                              const TestProcChangedMem: Integer;
  91.                              out   ErrorMsg: string): boolean; overload;
  92.     function GetMemoryUseMsg(const FailOnMemoryRecovery: boolean;
  93.                              const TestSetupChangedMem: Integer;
  94.                              const TestProcChangedMem: Integer;
  95.                              const TestTearDownChangedMem: Integer;
  96.                              const TestCaseChangedMem: Integer;
  97.                              out   ErrorMsg: string): boolean; overload;
  98.   end;
  99. implementation
  100. {$IFNDEF VER180}
  101.   uses
  102.   SysUtils;
  103. {$ENDIF}
  104. { TMemLeakMonitor }
  105. constructor TMemLeakMonitor.Create;
  106. begin
  107.   inherited;
  108.   GetMemoryManagerState(FMS1);
  109. end;
  110. function TMemLeakMonitor.MemLeakDetected(out LeakSize: Integer): boolean;
  111. var
  112.   I: Integer;
  113.   SMBSize1,
  114.   SMBSize2: Int64;
  115. begin
  116.   LeakSize  := 0;
  117.   SMBSize1 := 0;
  118.   SMBSize2 := 0;
  119.   GetMemoryManagerState(FMS2);
  120.   for I := 0 to NumSmallBlockTypes - 1 do // Iterate through the blocks
  121.   begin
  122.     Inc(SMBSize1, (FMS1.SmallBlockTypeStates[i].InternalBlockSize *
  123.                    FMS1.SmallBlockTypeStates[i].AllocatedBlockCount));
  124.     Inc(SMBSize2, (FMS2.SmallBlockTypeStates[i].InternalBlockSize *
  125.                    FMS2.SmallBlockTypeStates[i].AllocatedBlockCount));
  126.   end;
  127.   LeakSize := (SMBSize2 - SMBSize1);
  128.   LeakSize := LeakSize +
  129.     (Int64(FMS2.TotalAllocatedMediumBlockSize) - Int64(FMS1.TotalAllocatedMediumBlockSize)) +
  130.     (Int64(FMS2.TotalAllocatedLargeBlockSize) - Int64(FMS1.TotalAllocatedLargeBlockSize));
  131.   Result := LeakSize <> 0;
  132. end;
  133. // May be called after detecting memory use change at Test Procedure level
  134. function TDUnitMemLeakMonitor.GetMemoryUseMsg(const FailOnMemoryRecovery: boolean;
  135.                                               const TestProcChangedMem: Integer;
  136.                                               out   ErrorMsg: string): boolean;
  137. begin
  138.   ErrorMsg := '';
  139.   if (TestProcChangedMem > 0) then
  140.     ErrorMsg := IntToStr(TestProcChangedMem) +
  141.       ' Bytes Memory Leak in Test Procedure'
  142.   else
  143.   if (TestProcChangedMem  < 0) and (FailOnMemoryRecovery) then
  144.     ErrorMsg := IntToStr(Abs(TestProcChangedMem)) +
  145.      ' Bytes Memory Recovered in Test Procedure';
  146.   Result := (Length(ErrorMsg) = 0);
  147. end;
  148. function TDUnitMemLeakMonitor.MemLeakDetected(const AllowedLeakSize: Integer;
  149.                                               const FailOnMemoryRecovery: boolean;
  150.                                               out   LeakSize: Integer): boolean;
  151. begin
  152.   LeakSize := 0;
  153.   inherited MemLeakDetected(LeakSize);
  154.   Result := ((LeakSize > 0) and (LeakSize <> AllowedLeakSize)) or
  155.     ((LeakSize < 0) and (FailOnMemoryRecovery) and (LeakSize <> AllowedLeakSize));
  156. end;
  157. procedure TDUnitMemLeakMonitor.MarkMemInUse;
  158. begin
  159.   GetMemoryManagerState(FMS1);
  160. end;
  161. function TDUnitMemLeakMonitor.MemLeakDetected(const AllowedValuesGetter: TListIterator;
  162.                                               const FailOnMemoryRecovery: Boolean;
  163.                                               out   LeakIndex: integer;
  164.                                               out   LeakSize: Integer): Boolean;
  165. var
  166.   AllowedLeakSize: Integer;
  167. begin
  168.   LeakIndex := 0;
  169.   LeakSize  := 0;
  170.   Result := False;
  171.   inherited MemLeakDetected(LeakSize);
  172.   if (LeakSize = 0) then
  173.     exit;
  174.   // Next line access value stored via SetAllowedLeakSize, if any
  175.   if LeakSize = AllowedValuesGetter then
  176.     Exit;
  177.   repeat // loop over values stored via SetAllowedLeakArray
  178.     inc(LeakIndex);
  179.     AllowedLeakSize := AllowedValuesGetter;
  180.     if (LeakSize = AllowedLeakSize) then
  181.       Exit;
  182.   until (AllowedLeakSize = 0);
  183.   Result := (LeakSize > 0) or ((LeakSize < 0) and FailOnMemoryRecovery);
  184. end;
  185. // Expanded message generation for detected leak isolation
  186. // Use additional knowledge of when Setup and or TearDown have nor run.
  187. function TDUnitMemLeakMonitor.GetMemoryUseMsg(const FailOnMemoryRecovery: boolean;
  188.                                               const TestSetupChangedMem: integer;
  189.                                               const TestProcChangedMem: Integer;
  190.                                               const TestTearDownChangedMem: integer;
  191.                                               const TestCaseChangedMem: Integer;
  192.                                               out   ErrorMsg: string): boolean;
  193. var
  194.   Location: string;
  195. begin
  196.   Result := False;
  197.   ErrorMsg := '';
  198.   if (TestSetupChangedMem = 0) and (TestProcChangedMem = 0) and
  199.      (TestTearDownChangedMem = 0) and (TestCaseChangedMem <> 0) then
  200.   begin
  201.     ErrorMsg :=
  202.       'Error in TestFrameWork. No leaks in Setup, TestProc or Teardown but '+
  203.       IntToStr(TestCaseChangedMem) +
  204.       ' Bytes Memory Leak reported across TestCase';
  205.     Exit;
  206.   end;
  207.   if (TestSetupChangedMem + TestProcChangedMem + TestTearDownChangedMem) <>
  208.     TestCaseChangedMem then
  209.   begin
  210.     ErrorMsg :=
  211.       'Error in TestFrameWork. Sum of Setup, TestProc and Teardown leaks <> '+
  212.       IntToStr(TestCaseChangedMem) +
  213.       ' Bytes Memory Leak reported across TestCase';
  214.     Exit;
  215.   end;
  216.   Result := True;
  217.   if TestCaseChangedMem = 0 then
  218.     Exit;  // Dont waste further time here
  219.   if (TestCaseChangedMem < 0) and not FailOnMemoryRecovery then
  220.     Exit;     // Dont waste further time here
  221. // We get to here because there is a memory use imbalance to report.
  222.   if (TestCaseChangedMem > 0) then
  223.     ErrorMsg := IntToStr(TestCaseChangedMem) + ' Bytes memory leak  ('
  224.   else
  225.     ErrorMsg := IntToStr(TestCaseChangedMem) + ' Bytes memory recovered  (';
  226.   Location := '';
  227.   if (TestSetupChangedMem <> 0) then
  228.     Location := 'Setup= ' + IntToStr(TestSetupChangedMem) + '  ';
  229.   if (TestProcChangedMem <> 0) then
  230.     Location := Location + 'TestProc= ' + IntToStr(TestProcChangedMem) + '  ';
  231.   if (TestTearDownChangedMem <> 0) then
  232.     Location := Location + 'TearDown= ' + IntToStr(TestTearDownChangedMem) + '  ';
  233.   ErrorMsg := ErrorMsg + Location + ')';
  234.   Result := (Length(ErrorMsg) = 0);
  235. end;
  236. end.