home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue48 / Memory / MemUseU.pas < prev   
Encoding:
Pascal/Delphi Source File  |  1999-06-22  |  5.7 KB  |  192 lines

  1. unit MemUseU;
  2.  
  3. {$ifdef Ver90} { Delphi 2.0x }
  4.   {$define DelphiLessThan4}
  5. {$endif}
  6. {$ifdef Ver93} { C++ Builder 1.0x }
  7.   {$define DelphiLessThan4}
  8. {$endif}
  9. {$ifdef Ver100} { Delphi 3.0x }
  10.   {$define DelphiLessThan4}
  11. {$endif}
  12. {$ifdef Ver110} { C++ Builder 3.0x }
  13.   {$define DelphiLessThan4}
  14. {$endif}
  15.  
  16. interface
  17.  
  18. uses
  19.   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  20.   ExtCtrls, StdCtrls;
  21.  
  22. type
  23.   TForm1 = class(TForm)
  24.     tmrHeapMonitor: TTimer;
  25.     pnlActions: TPanel;
  26.     btnNewEdits: TButton;
  27.     btnClearEdits: TButton;
  28.     Label1: TLabel;
  29.     procedure tmrHeapMonitorTimer(Sender: TObject);
  30.     procedure btnNewEditsClick(Sender: TObject);
  31.     procedure FormCreate(Sender: TObject);
  32.     procedure FormDestroy(Sender: TObject);
  33.     procedure btnClearEditsClick(Sender: TObject);
  34.   private
  35.     EditList: TList;
  36.   end;
  37.  
  38. var
  39.   Form1: TForm1;
  40.  
  41. implementation
  42.  
  43. {$R *.DFM}
  44.  
  45. procedure TForm1.FormCreate(Sender: TObject);
  46.  
  47.   function FindHMCommand: Boolean;
  48. {$ifdef DelphiLessThan4}
  49.   var
  50.     I: Integer;
  51.   begin
  52.     Result := False;
  53.     for I := 1 to ParamCount do
  54.       if (UpperCase(ParamStr(I)) = '/HM') or
  55.         (UpperCase(ParamStr(I)) = '-HM') then
  56.         Result := True;
  57. {$else}
  58.   begin
  59.     Result := FindCmdLineSwitch('HM', ['/', '-'], True)
  60. {$endif}
  61.   end;
  62.  
  63. begin
  64.   if FindHMCommand then
  65.   begin
  66.     //Enable heap monitoring (via timer)
  67.     tmrHeapMonitor.Enabled := True;
  68.     //Make the timer tick straight away
  69.     tmrHeapMonitor.OnTimer(tmrHeapMonitor);
  70.   end;
  71.   EditList := TList.Create;
  72. end;
  73.  
  74. procedure TForm1.FormDestroy(Sender: TObject);
  75. begin
  76.   EditList.Free
  77. end;
  78.  
  79. procedure TForm1.btnNewEditsClick(Sender: TObject);
  80. var
  81.   Edit: TEdit;
  82.   I: Integer;
  83. begin
  84.   for I := 1 to 20 do
  85.   begin
  86.     Edit := TEdit.Create(Self);
  87.     EditList.Add(Edit);
  88.     with Edit do
  89.     begin
  90.       Left := Random(Self.ClientWidth - Width - 1);
  91.       Top := pnlActions.Height + Random(Self.ClientHeight - pnlActions.Height - Height - 1);
  92.       Color := Random($1000000);
  93.       Text := Format('$%x', [Color]);
  94.       Parent := Self
  95.     end;
  96.   end;
  97.   pnlActions.BringToFront;
  98. end;
  99.  
  100. procedure TForm1.btnClearEditsClick(Sender: TObject);
  101. begin
  102.   while EditList.Count > 0 do
  103.   begin
  104.     TEdit(EditList[0]).Free;
  105.     EditList.Delete(0)
  106.   end;
  107. end;
  108.  
  109. function CommittedMemorySize: DWord;
  110. var
  111.   MBI: TMemoryBasicInformation;
  112.   SI: TSystemInfo;
  113.   RangeStart: Pointer;
  114. begin
  115.   Result := 0;
  116.   GetSystemInfo(SI);
  117.   RangeStart := SI.lpMinimumApplicationAddress;
  118.   while DWord(RangeStart) < DWord(SI.lpMaximumApplicationAddress) do
  119.   begin
  120.     VirtualQuery(RangeStart, MBI, SizeOf(MBI));
  121.     //Only get committed memory (storage allocated for this)
  122.     if MBI.State = MEM_COMMIT then
  123.       Inc(Result, MBI.RegionSize);
  124.     //Delphi 2 & 3 could only handle $7FFFFFFF as biggest int
  125.     //Last region is likely to end at $80000000. To avoid integer
  126.     //overflow, we'll do a comparison and bypass the addition
  127.     if DWord(SI.lpMaximumApplicationAddress) - MBI.RegionSize >= DWord(RangeStart) then
  128.       Inc(PChar(RangeStart), MBI.RegionSize)
  129.     else
  130.       //If overflow would have occurred, loop is over
  131.       Break
  132.   end;
  133. end;
  134.  
  135. const
  136.   //These come from Delphi's Source\RTL\GetMem.inc file
  137.   cHeapOk           = 0;  // everything's fine
  138.   cReleaseErr       = 1;  // operating system returned an error when we released
  139.   cDecommitErr      = 2;  // operating system returned an error when we decommited
  140.   cBadCommittedList = 3;  // list of committed blocks looks bad
  141.   cBadFiller1       = 4;  // filler block is bad
  142.   cBadFiller2       = 5;  // filler block is bad
  143.   cBadFiller3       = 6;  // filler block is bad
  144.   cBadCurAlloc      = 7;  // current allocation zone is bad
  145.   cCantInit         = 8;  // couldn't initialize
  146.   cBadUsedBlock     = 9;  // used block looks bad
  147.   cBadPrevBlock     = 10; // prev block before a used block is bad
  148.   cBadNextBlock     = 11; // next block after a used block is bad
  149.   cBadFreeList      = 12; // free list is bad
  150.   cBadFreeBlock     = 13; // free block is bad
  151.   cBadBalance       = 14; // free list doesn't correspond to blocks marked free
  152.  
  153. function HeapErrorDesc(Error: Cardinal): String;
  154. begin
  155.   case Error of
  156.     cHeapOk:           Result := 'Everything''s fine';
  157.     cReleaseErr:       Result := 'OS returned an error when we released';
  158.     cDecommitErr:      Result := 'OS returned an error when we decommited';
  159.     cBadCommittedList: Result := 'List of committed blocks looks bad';
  160.     cBadFiller1,
  161.     cBadFiller2,
  162.     cBadFiller3:       Result := 'Filler block is bad';
  163.     cBadCurAlloc:      Result := 'Current allocation zone is bad';
  164.     cCantInit:         Result := 'Couldn''t initialize';
  165.     cBadUsedBlock:     Result := 'Used block looks bad';
  166.     cBadPrevBlock:     Result := 'Prev block before a used block is bad';
  167.     cBadNextBlock:     Result := 'Next block after a used block is bad';
  168.     cBadFreeList:      Result := 'Free list is bad';
  169.     cBadFreeBlock:     Result := 'Free block is bad';
  170.     cBadBalance:       Result := 'Free list doesn''t correspond to blocks marked free';
  171.   end
  172. end;
  173.  
  174. procedure TForm1.tmrHeapMonitorTimer(Sender: TObject);
  175. var
  176.   HS: THeapStatus;
  177. begin
  178.   HS := GetHeapStatus;
  179.   if HS.HeapErrorCode = cHeapOk then
  180.     Application.MainForm.Caption := Format(
  181.       '%s (App: Blocks=%d Bytes=$%x (%2:d) Win32: Committed=$%x (%3:d))',
  182.       [Application.Title, AllocMemCount, AllocMemSize, CommittedMemorySize])
  183.   else
  184.     Application.MainForm.Caption := Format(
  185.       '%s (Invalid heap code %d: %s)',
  186.       [Application.Title, HS.HeapErrorCode, HeapErrorDesc(HS.HeapErrorCode)]);
  187. end;
  188.  
  189. initialization
  190.   Randomize;
  191. end.
  192.