== Debugging a Delphi Application ==
== Using Memory Profiler ==
=== Project Setup ===
# Project > Options > Compiler
#* Code Generation:
#** Optimization
#** Stack Frames
#* Debugging:
#** Debug Information
# Project > Options > Linker
#* Include TD32 debug info
#* Map File: Detailed
# Build project (Project > Build All Projects).
=== AQTime ===
# Run AQTime and include project executable to debug (File > Open > choose the .exe file).
# Select profiler to execute: Options > Profile Options (or from drop-down in toolbar). Use VCL > VCL Class Profiler.
# Run executable with profiler (Project > Run).
# Test and push the executable to try to break it. Once you are done with tests, simply quit the application.
# Review memory leaks report in AQTime (it takes a few seconds to update after the tested application has exited).
== Using Built-in Debugging Tools ==
=== Using FastMM ===
# Download [[http://fastmm.sourceforge.net|FastMM (Fast Memory Manager)]], and [[http://jedqc.blogspot.com/2007/07/new-fastmm4-options-interface.html|FastMM Options Interface GUI]]
# Open project in Delphi.
# Install FastMM in your project and source code (see instructions distributed with FastMM package).
# Set ''FullDebugMode'' in Project > Options > Directories/Conditionals > Conditional defines.
# Build project (Project > Build All Projects).
# Execute project as usual. A dialog will popup if there are any critical errors or memory leaks during run time.
Example, in ''MyProject.dpr'':
program MyProject;
{$DEFINE FullDebugMode} // for software that needs debug reporting using FastMM4
uses
FastMM4 {memory manager replacement (and mem leak detector)},
Forms,
Windows,
sysUtils,
messages,
Dialogs,
Classes;
begin
OutputDebugString(pchar('DBGVIEWCLEAR')); // clear DebugView window (get from www.sysinternals.com)
// register with FastMM4 some known memory leaks
RegisterExpectedMemoryLeak(28 {21-28}, 1); // TCriticalSection x 1
RegisterExpectedMemoryLeak(44 {37-44}, 1); // TShellFolder x 1
RegisterExpectedMemoryLeak(60 {45-60}, 1); // TStringList x 1
FastMM4.ReportMemoryLeaksOnShutdown := DebugHook <> 0; // report leaks only when using debugger
. . . project code here . . .
end.
In ''FastMM4Options.inc'', enable the following define statements:
{$define UseOutputDebugString}
{$define LogErrorsToFile}
{$define LogMemoryLeakDetailToFile}
{$define ClearLogFileOnStartup}
{$define EnableMemoryLeakReporting}
{$define HideExpectedLeaksRegisteredByPointer}
{$define RequireDebuggerPresenceForLeakReporting}
{$define RequireDebugInfoForLeakReporting}
==== References ====
* New Memory Manage in BDS 2006: http://dn.codegear.com/articles/33416
* JED's GUI: http://jedqc.blogspot.com/2007/07/new-fastmm4-options-interface.html
=== Using EventLog or DebugView ===
Create some debugging routines in ''DebugTools.pas'' (Pascal unit):
//------------------------------------------------------------------------------
// Unit Name: DebugTools
// Author: Siegwart Mayr
// Date: 17-May-2006
// Purpose: Library with debugging routines.
//------------------------------------------------------------------------------
unit DebugTools;
interface
Uses
Windows, Forms;
//-------------------------------------------
// types
//-------------------------------------------
Type
TOutlineNodeType = (ntEmpty, ntNode, ntLeaf);
//-------------------------------------------
// function prototypes
//-------------------------------------------
procedure DebugMsg(str: string; OutlineLevel: integer=0; NodeType: TOutlineNodeType=ntNode);
procedure DebugStr(str: string);
//-------------------------------------------
// resource strings
//-------------------------------------------
ResourceString
rsOutlineBullet = '+';
rsOutlineLeaf = '-';
rsOutlineEmpty = '|';
implementation
//------------------------------------------------------------------------------
// description: Send the specified string to the Windows debugger environment,
// so that it can be viewed with DbgViewer (http://www.sysinternals.com)
// parameters : str: string, OutlineLevel: integer, NoteType: TOutlineNodeType
// return : None
//------------------------------------------------------------------------------
procedure DebugMsg(str: string; OutlineLevel: integer=0; NodeType: TOutlineNodeType=ntNode);
{$ifdef FullDebugMode}
var
LevelSpacer: string;
NodeSymbol: string;
{$endif}
begin
{$ifdef FullDebugMode}
case NodeType of
ntEmpty: NodeSymbol := rsOutlineEmpty;
ntNode: NodeSymbol := rsOutlineBullet + rsOutlineBullet;
ntLeaf: NodeSymbol := rsOutlineBullet + rsOutlineLeaf;
else
NodeSymbol := rsOutlineBullet;
end;
case OutlineLevel of
1: begin
LevelSpacer := StringOfChar(' ', 1) + NodeSymbol;
end;
2: begin
LevelSpacer := StringOfChar(' ', 2) + NodeSymbol;
end;
3: begin
LevelSpacer := StringOfChar(' ', 3) + NodeSymbol;
end;
else
LevelSpacer := '';
end;
OutputDebugString(pchar(LevelSpacer + ' ' + str));
{$endif}
end;
//------------------------------------------------------------------------------
// description: Simple debugging routine.
// parameters : str: string
// return : None
//------------------------------------------------------------------------------
procedure DebugStr(str: string);
begin
//{$ifdef FullDebugMode}
OutputDebugString(pchar(str));
//{$endif}
end;
end.
# Include ''DebugTools'' in the ''Uses'' clause in the Delphi source code.
# Insert ''DebugStr('My debug message here...')'' statements in the source code whenever something needs debugging.
# Use one of these utilities to view debug messages as application is being executed:
#* When application is run from Delphi's IDE: use Delphi's built-in Event Log (View > Debug Windows > Event Log (Ctrl-Alt-V)).
#* When application is run by itself: use ''DbgView.exe'' utility (from http://www.sysinternals.com). Leave utility running while application is run as well.