forked from andremussche/scalemm
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathHeapMM.pas
172 lines (150 loc) · 5.31 KB
/
HeapMM.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
{
Alternative memory manager. To use it, just place a reference to this
unit *FIRST* in the uses clause of your project (dpr-file). It is a good idea
to use this memory manager with system dcu replacement by Vladimir Kladov.
Heap API used, which is fast and very effective (allocated block granularity
is 16 bytes). One additional benefit is that some proofing tools (MemProof)
do not detect API failures, which those can find when standard Delphi memory
manager used.
=====================================================================
Copyright (C) by Vladimir Kladov, 2001
---------------------------------------------------------------------
http://xcl.cjb.net
mailto: [email protected]
}
unit HeapMM;
interface
uses windows;
const
HEAP_NO_SERIALIZE = $00001;
HEAP_GROWABLE = $00002;
HEAP_GENERATE_EXCEPTIONS = $00004;
HEAP_ZERO_MEMORY = $00008;
HEAP_REALLOC_IN_PLACE_ONLY = $00010;
HEAP_TAIL_CHECKING_ENABLED = $00020;
HEAP_FREE_CHECKING_ENABLED = $00040;
HEAP_DISABLE_COALESCE_ON_FREE = $00080;
HEAP_CREATE_ALIGN_16 = $10000;
HEAP_CREATE_ENABLE_TRACING = $20000;
HEAP_MAXIMUM_TAG = $00FFF;
HEAP_PSEUDO_TAG_FLAG = $08000;
HEAP_TAG_SHIFT = 16 ;
{$DEFINE USE_PROCESS_HEAP}
var
HeapHandle: THandle;
{* Global handle to the heap. Do not change it! }
HeapFlags: DWORD = 0;
{* Possible flags are:
HEAP_GENERATE_EXCEPTIONS - system will raise an exception to indicate a
function failure, such as an out-of-memory
condition, instead of returning NULL.
HEAP_NO_SERIALIZE - mutual exclusion will not be used while the HeapAlloc
function is accessing the heap. Be careful!
Not recommended for multi-thread applications.
But faster.
HEAP_ZERO_MEMORY - obviously. (Slower!)
}
{ Note from MSDN:
The granularity of heap allocations in Win32 is 16 bytes. So if you
request a global memory allocation of 1 byte, the heap returns a pointer
to a chunk of memory, guaranteeing that the 1 byte is available. Chances
are, 16 bytes will actually be available because the heap cannot allocate
less than 16 bytes at a time.
}
type
TMemHeader = object
/// the memory block handler which owns this memory block
//Owner: PMemBlock;
/// linked to next single memory item (other thread freem mem)
//NextMem: PMemHeader;
Size: NativeUInt;
end;
PMemHeader = ^TMemHeader;
implementation
// Allocate memory block.
function HeapGetMem(aSize: Integer): Pointer;
var
iSize: Integer;
begin
iSize := aSize + SizeOf(TMemHeader) + (aSize shr 3); {1/8 extra}
Result := HeapAlloc( HeapHandle, HeapFlags, iSize );
TMemHeader(Result^).Size := iSize;
Result := Pointer(NativeUInt(Result) + SizeOf(TMemHeader));
end;
// Deallocate memory block.
function HeapFreeMem(aMemory: Pointer): Integer;
var
ph: PMemHeader;
begin
ph := PMemHeader(NativeUInt(aMemory) - SizeOf(TMemHeader));
Result := Integer(not HeapFree(HeapHandle, HeapFlags and HEAP_NO_SERIALIZE, ph) );
end;
// Resize memory block.
function HeapReallocMem(aMemory: Pointer; aSize: Integer): Pointer;
var
ph: PMemHeader;
iSize: Integer;
begin
ph := PMemHeader(NativeUInt(aMemory) - SizeOf(TMemHeader));
iSize := aSize + SizeOf(TMemHeader);
// iSize := iSize + (aSize shr 3); {1/8 extra}
// new size smaller than current size?
if (NativeUInt(iSize) <= ph.Size) then
begin
if NativeUInt(iSize) >= (ph.Size shr 2) then
begin
Result := aMemory; // no resize needed up to half the current item size -> now a quarter, benchmark optimization...
Exit;
end
end;
{
// too much downscaling: use move
else
begin
Result := HeapGetMem(aSize); // new mem
if aMemory <> Result then
begin
Move(aMemory^, Result^, aSize); // copy (use smaller new size)
HeapFreeMem(aMemory); // free old mem
end;
end;
end
else
begin
// new size bigger than current size
Result := HeapGetMem(aSize); // new mem
if aMemory <> Result then
begin
Move(aMemory^, Result^, ph.Size); // copy (use smaller old size)
HeapFreeMem(aMemory); // free old mem
end;
end;
}
Result := HeapRealloc( HeapHandle, HeapFlags and (HEAP_NO_SERIALIZE and
HEAP_GENERATE_EXCEPTIONS and HEAP_ZERO_MEMORY),
// (Prevent using flag HEAP_REALLOC_IN_PLACE_ONLY here - to allow
// system to move the block if necessary).
ph, iSize );
TMemHeader(Result^).Size := iSize;
Result := Pointer(NativeUInt(Result) + SizeOf(TMemHeader));
end;
const
HeapMemoryManager: TMemoryManager = (
GetMem: HeapGetMem;
FreeMem: HeapFreeMem;
ReallocMem: HeapReallocMem);
var OldMM: TMemoryManager;
initialization
{$IFDEF USE_PROCESS_HEAP}
HeapHandle := GetProcessHeap;
{$ELSE}
HeapHandle := HeapCreate( 0, 0, 0 );
{$ENDIF}
GetMemoryManager( OldMM );
SetMemoryManager( HeapMemoryManager );
finalization
SetMemoryManager( OldMM );
{$IFNDEF USE_PROCESS_HEAP}
HeapDestroy( HeapHandle );
{$ENDIF}
end.