ueToFlagErrors;
fNext := NodeList;
NodeList := Self;
end;
// If you want to clean up the list properly when the application
// finishes, call RealFree for each node in the list. The inherited
// FreeInstance method frees and cleans up the node for real.
procedure TNode.RealFree;
begin
inherited FreeInstance;
end;
You can also replace the entire memory management system that Delphi uses. Install a new memory manager by calling SetMemoryManager. For example, you might want to replace Delphi''''s suballocator with an allocator that performs additional error checking. Example 2-18 shows a custom memory manager that keeps a list of pointers the program has allocated and explicitly checks each attempt to free a pointer against the list. Any attempt to free an invalid pointer is refused, and Delphi will report a runtime error (which SysUtils changes to an exception). As a bonus, the memory manager checks that the list is empty when the application ends. If the list is not empty, you have a memory leak.
Example 2-18: Installing a Custom Memory Manager unit CheckMemMgr;
interface
uses Windows;
function CheckGet(Size: Integer): Pointer;
function CheckFree(Mem: Pointer): Integer;
function CheckRealloc(Mem: Pointer; Size: Integer): Pointer;
var
HeapFlags: DWord; // In a single-threaded application, you might
// want to set this to Heap_No_Serialize.
implementation
const
MaxSize = MaxInt div 4;
type
TPointerArray = array[1..MaxSize] of Pointer;
PPointerArray = ^TPointerArray;
var
Heap: THandle; // Windows heap for the pointer list
List: PPointerArray; // List of allocated pointers
ListSize: Integer; // Number of pointers in the list
ListAlloc: Integer; // Capacity of the pointer list
// If the list of allocated pointers is not empty when the program
// finishes, that means you have a memory leak. Handling the memory
// leak is left as an exercise for the reader.
procedure MemoryLeak;
begin
// Report the leak to the user, but remember that the program is
// shutting down, so you should probably stick to the Windows API
// and not use the VCL.
end;
// Add a pointer to the list.
procedure AddMem(Mem: Pointer);
begin
if List = nil then
begin
// New list of pointers.
ListAlloc := 8;
List := HeapAlloc(Heap, HeapFlags, ListAlloc * SizeOf(Pointer));
end
else if ListSize >= ListAlloc then
begin
// Make the list bigger. Try to do it somewhat intelligently.
if ListAlloc < 256 then
ListAlloc := ListAlloc * 2
else
ListAlloc := ListAlloc + 256;
List := HeapRealloc(Heap, HeapFlags, List,
ListAlloc * SizeOf(Pointer));
end;
// Add a pointer to the list.
Inc(ListSize);
List[ListSize] := Mem;
end;
// Look for a pointer in the list, and remove it. Return True for
// success, and False if the pointer is not in the list.
function RemoveMem(Mem: Pointer): Boolean;
var
I: Integer;
begin
for I := 1 to ListSize do
if List[I] = Mem then
begin
MoveMemory(@List[I], @List[I+1], (ListSize-I) * SizeOf(Pointer));
Dec(ListSize);
Result := True;
Exit;
end;
Result := False;
end;
// Replacement memory allocator.
function CheckGet(Size: Integer): Pointer;
begin
Result := SysGetMem(Size);
AddMem(Result);
end;
// If the pointer isn''''t in the list, don''''t call the real
// Free function. Return 0 for success, and non-zero for an error.
function CheckFree(Mem: Pointer): Integer;
begin
if not RemoveMem(Mem) then
Result := 1
else
Result := SysFreeMem(Mem);
end;
// Remove the old pointer and add the new one, which might be the
// same as the old one, or it might be different. Return nil for
// an error, and Delphi will raise an exception.
function CheckRealloc(Mem: Pointer; Size: Integer): Pointer;
begin
if not RemoveMem(Mem) then
Result := nil
else
begin
Result :=SysReallocMem(Mem, Size);
AddMem(Result);
end;
end;
procedure SetNewManager;
var
Mgr: TMemoryManager;
begin
Mgr.GetMem := CheckGet;
Mgr.FreeMem := CheckFree;
Mgr.ReallocMem := CheckRealloc;
SetMemoryManager(Mgr);
end;
initialization
Heap := HeapCreate(0, HeapFlags, 0);
SetNewManager;
finalization
if ListSize <> 0 then
MemoryLeak;
HeapDestroy(Heap);
end.
If you define a custom memory manager, you must ensure that your memory manager is used for all memory allocation. The easiest way to do this is to set the memory manager in a unit''''s initialization section, as shown in Example 2-18. The memory management unit must be the first unit listed in the project''''s uses declaration.
Ordinarily, if a unit makes global changes in its initialization section, it should clean up those changes in its finalization section. A unit in a package might be loaded and unloaded many times in a single application, so cleaning up is important. A memory manager is different, though. Memory allocated by one manager cannot be freed by another manager, so you must ensure that only one manager is active in an application, and that the manager is active for the entire duration of the application. This means you must not put your memory manager in a package, although you can use a DLL, as explained in the next section.
Memory and DLLs
If you use DLLs and try to pass objects between DLLs or between the application and a DLL, you run into a number of problems. First of all, each DLL and EXE keeps its own copy of its class tables. The is and as operators do not work correctly for objects passed between DLLs and EXEs. Use packages (described in Chapter 1) to solve this problem. Another problem is that any memory allocated in a DLL is owned by that DLL. When Windows unloads the DLL, all memory allocated by the DLL is freed, even if the EXE or another DLL holds a pointer to that memory. This can be a major problem when using strings, dynamic arrays, and Variants because you never know when Delphi will allocate memory automatically.
The solution is to use the ShareMem unit as the first unit of your project and every DLL. The ShareMem unit installs a custom memory manager that redirects all memory allocation requests to a special DLL, BorlndMM.dll. The application doesn''''t unload BorlndMM until the application exits. The DLL magic takes place transparently, so you don''''t need to worry about the details. Just make sure you use the ShareMem unit, and make sure it is the first unit used by your program and libraries. When you release your application to your clients or customers, you will need to include BorlndMM.dll.
If you define your own memory manager, and you need to use DLLs, you must duplicate the magic performed by the ShareMem unit. You can replace ShareMem with your own unit that forwards memory requests to your DLL, which uses your custom memory manager. Example 2-19 shows one way to define your own replacement for the ShareMem unit.
Example 2-19: Defining a Shared Memory Manager unit CheckShareMem;
// Use this unit first so all memory allocations use the shared
// memory manager. The application and all DLLs must use this unit.
// You cannot use packages because those DLLs use the default Borland
// shared memory manager.
interface
function CheckGet(Size: Integer): Pointer;
function CheckFree(Mem: Pointer): Integer;
function CheckRealloc(Mem: Pointer; Size: Integer): Pointer;
implementation
const
DLL = ''''CheckMM.dll'''';
function CheckGet(Size: Integer): Pointer; external DLL;
function CheckFree(Mem: Pointer): Integer; external DLL;
function CheckRealloc(Mem: Pointer; Size: Integer): Pointer;
external DLL;
procedure SetNewManager;
var
Mgr: TMemoryManager;
begin
Mgr.GetMem := CheckGet;
Mgr.FreeMem := CheckFree;
Mgr.ReallocMem := CheckRealloc;
SetMemoryManager(Mgr);
end;
initialization
SetNewManager;
end.
The CheckMM DLL uses your custom memory manager and exports its functions so they can be used by the CheckShareMem unit. Example 2-20 shows the source code for the CheckMM library.
Example 2-20: Defining the Shared Memory Manager DLL library CheckMM;
// Replacement for BorlndMM.dll to use a custom memory manager.
uses
CheckMemMgr;
exports
CheckGet, CheckFree, CheckRealloc;
begin
end.
Your program and library projects use the CheckShareMem unit first, and all memory requests go to CheckMM.dll, which uses the error-checking memory manager. You don''''t often need to replace Delphi''''s memory manager, but as you can see, it isn''''t difficult to do.
TIP: The memory manager that comes with Delphi works well for most applications, but it does not perform well in some cases. The average application allocates and frees memory in chunks of varying sizes. If your application is different and allocates memory in ever-increasing sizes (say, because you have a dynamic array that grows in small steps to a very large size), performance will suffer. Delphi''''s memory manager will allocate more memory than your application needs. One solution is to redesign your program so it uses memory in a different pattern (say, by preallocating a large dynamic array). Another solution is to write a memory manager that better meets the specialized needs of your application. For example, the new memory manager might use the Windows API (HeapAllocate, etc.).
Old-Style Object Types
In addition to class types, Delphi supports an obsolete type that uses the object keyword. Old-style objects exist for backward compatibi 上一页 [1] [2] [3] 下一页 [系统软件]InstallShield Express for delphi制作安装程序定… [系统软件]The GRETA Regular Expression Template Archive [系统软件]OLE with the internet explorer [系统软件]14.5.10.1 Object creation expressions [常用软件]InstallShield Express制作Delphi数据库安装程序 [常用软件]Firefox: What’s the next step? [VB.NET程序]VB.Net中文教程(8) 对象(Object)基本概念 [VB.NET程序]The UDPChat Source(VB.NET) [Delphi程序]为什么选择Delphi.Net ? [Delphi程序]《关于VisiBroker For Delphi的使用》(4)
|