-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathFastMM5.pas
10419 lines (8950 loc) · 390 KB
/
FastMM5.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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
{
FastMM 5.04
Description:
A fast replacement memory manager for Embarcadero Delphi applications that scales well across multiple threads and CPU
cores, is not prone to memory fragmentation, and supports shared memory without the use of external .DLL files.
Developed by:
Pierre le Riche, copyright 2004 - 2021, all rights reserved
Sponsored by:
gs-soft AG
Homepage:
https://github.com/pleriche/FastMM5
Licence:
FastMM 5 is dual-licensed. You may choose to use it under the restrictions of the GPL v3 licence at no cost to you,
or you may purchase a commercial licence. A commercial licence grants you the right to use FastMM5 in your own
applications, royalty free, and without any requirement to disclose your source code nor any modifications to FastMM
to any other party. A commercial licence lasts into perpetuity, and entitles you to all future updates, free of
charge. A commercial licence is sold per developer developing applications that use FastMM, as follows:
1 developer = $99
2 developers = $189
3 developers = $269
4 developers = $339
5 developers = $399
>5 developers = $399 + $50 per developer from the 6th onwards
site licence = $999 (unlimited number of developers affiliated with the owner of the licence, i.e. employees,
co-workers, interns and contractors)
Please send an e-mail to fastmm@leriche.org to request an invoice before or after payment is made. Payment may be
made via PayPal at https://www.paypal.me/fastmm (paypal@leriche.org), or via bank transfer. Bank details will be
provided on the invoice.
Support (via e-mail) is available for users with a commercial licence. Enhancement requests submitted by users with a
commercial licence will be prioritized.
Usage Instructions:
Add FastMM5.pas as the first unit in your project's DPR file. It will install itself automatically during startup,
replacing the default memory manager.
In order to share the memory manager between the main application and libraries call
FastMM_AttemptToUseSharedMemoryManager (in order to use the memory manager of another module in the process) or
FastMM_ShareMemoryManager (to share the memory manager instance of the current module with other modules). It is
important to share the memory manager between modules where memory allocated in the one module may be freed by the
other.
If the application requires memory alignment greater than the default, call FastMM_EnterMinimumAddressAlignment and
once the greater alignment is no longer required call FastMM_ExitMinimumAddressAlignment. Calls may be nested. The
coarsest memory alignment requested takes precedence.
At the cost of performance and increased memory usage FastMM can log additional metadata together with every block.
In order to enable this mode call FastMM_EnterDebugMode and to exit debug mode call FastMM_ExitDebugMode. Calls may
be nested in which case debug mode will be active as long as the number of FastMM_EnterDebugMode calls exceed the
number of FastMM_ExitDebugMode calls. In debug mode freed memory blocks will be filled with the byte pattern
$808080... so that usage of a freed memory block or object, as well as corruption of the block header and/or footer
will likely be detected. If the debug support library, FastMM_FullDebugMode.dll, is available and the application has
not specified its own handlers for FastMM_GetStackTrace and FastMM_ConvertStackTraceToText then the support library
will be loaded during the first call to FastMM_EnterDebugMode.
Events (memory leaks, errors, etc.) may be logged to file, displayed on-screen, passed to the debugger or any
combination of the three. Specify how each event should be handled via the FastMM_LogToFileEvents,
FastMM_MessageBoxEvents and FastMM_OutputDebugStringEvents variables. The default event log filename will be built
from the application filepath, but may be overridden via FastMM_SetEventLogFilename. Messages are built from
templates that may be changed/translated by the application.
The optimization strategy of the memory manager may be tuned via FastMM_SetOptimizationStrategy. It can be set to
favour performance, low memory usage, or a blend of both. The default strategy is to blend the performance and low
memory usage goals.
The following conditional defines are supported:
FastMM_FullDebugMode (or FullDebugMode) - If defined then FastMM_EnterDebugMode will be called on startup so that
the memory manager starts in debug mode. If FastMM_FullDebugMode is defined and FastMM_DebugLibraryDynamicLoading
(or LoadDebugDLLDynamically) is not defined then FastMM_DebugLibraryStaticDependency is implied.
FastMM_FullDebugModeWhenDLLAvailable (or FullDebugModeWhenDLLAvailable) - If defined an attempt will be made to load
the debug support library during startup. If successful then FastMM_EnterDebugMode will be called so that the
memory manager starts up in debug mode.
FastMM_DebugLibraryStaticDependency - If defined there will be a static dependency on the debug support library,
FastMM_FullDebugMode.dll (32-bit) or FastMM_FullDebugMode64.dll (64-bit). If FastMM_EnterDebugMode will be called
in the startup code and the memory manager will also be shared between an application and libraries, then it
may be necessary to enable this define in order to avoid DLL unload order issues during application shutdown
(typically manifesting as an access violation when attempting to report on memory leaks during shutdown).
It is a longstanding issue with Windows that it is not always able to unload DLLs in the correct order during
application shutdown when DLLs are loaded dynamically during startup. Note that while enabling this define will
introduce a static dependency on the debug support library, it does not actually enter debug mode by default -
FastMM_EnterDebugMode must still be called to enter debug mode, and FastMM_ExitDebugMode can be called to exit debug
mode at any time.
FastMM_ClearLogFileOnStartup (or ClearLogFileOnStartup) - When defined FastMM_DeleteEventLogFile will be called
during startup, deleting the event log file (if it exists).
FastMM_Align16Bytes (or Align16Bytes) - When defined FastMM_EnterMinimumAddressAlignment(maa16Bytes) will be called
during startup, forcing a minimum of 16 byte alignment for memory blocks. Note that this has no effect under 64
bit, since 16 bytes is already the minimum alignment.
FastMM_5Arenas, FastMM_6Arenas .. FastMM_16Arenas - Increases the number of arenas from the default values. See the
notes for the CFastMM_SmallBlockArenaCount constant for guidance on the appropriate number of arenas.
FastMM_DisableAutomaticInstall - Disables automatic installation of FastMM as the memory manager. If defined then
FastMM_Initialize should be called from application code in order to install FastMM, and FastMM_Finalize to
uninstall and perform the leak check (if enabled), etc.
FastMM_EnableMemoryLeakReporting (or EnableMemoryLeakReporting) - If defined then the memory leak summary and detail
will be added to the set of events logged to file (FastMM_LogToFileEvents) and the leak summary will be added to the
set of events displayed on-screen (FastMM_MessageBoxEvents).
FastMM_RequireDebuggerPresenceForLeakReporting (or RequireDebuggerPresenceForLeakReporting) - Used in conjunction
with EnableMemoryLeakReporting - if the application is not running under the debugger then the
EnableMemoryLeakReporting define is ignored.
FastMM_NoMessageBoxes (or NoMessageBoxes) - Clears the set of events that will cause a message box to be displayed
(FastMM_MessageBoxEvents) on startup.
FastMM_ShareMM (or ShareMM) - If defined then FastMM_ShareMemoryManager will be called during startup, sharing the
memory manager of the module if the memory manager of another module is not already being shared.
FastMM_ShareMMIfLibrary (or ShareMMIfLibrary) - If defined and the module is not a library then the ShareMM define
is disabled.
FastMM_AttemptToUseSharedMM (or AttemptToUseSharedMM) - If defined FastMM_AttemptToUseSharedMemoryManager will be
called during startup, switching to using the memory manager shared by another module (if there is a shared memory
manager).
FastMM_NeverUninstall (or NeverUninstall) - Sets the FastMM_NeverUninstall global variable to True. Use this if any
leaked pointers should remain valid after this unit is finalized.
PurePascal - The assembly language code paths are disabled, and only the Pascal code paths are used. This is
normally used for debugging purposes only.
Supported Compilers:
Delphi XE3 and later
Supported Platforms:
Windows, 32-bit and 64-bit
}
unit FastMM5;
interface
uses
Winapi.Windows;
{$RangeChecks Off}
{$BoolEval Off}
{$OverflowChecks Off}
{$Optimization On}
{$StackFrames Off}
{$TypedAddress Off}
{$LongStrings On}
{$Align 8}
{$Include FastMM5Options.inc}
{Translate legacy v4 defines to their current names.}
{$ifdef FullDebugMode} {$define FastMM_FullDebugMode} {$endif}
{$ifdef LoadDebugDLLDynamically} {$define FastMM_DebugLibraryDynamicLoading} {$endif}
{$ifdef FullDebugModeWhenDLLAvailable} {$define FastMM_FullDebugModeWhenDLLAvailable} {$endif}
{$ifdef ClearLogFileOnStartup} {$define FastMM_ClearLogFileOnStartup} {$endif}
{$ifdef Align16Bytes} {$define FastMM_Align16Bytes} {$endif}
{$ifdef EnableMemoryLeakReporting} {$define FastMM_EnableMemoryLeakReporting} {$endif}
{$ifdef RequireDebuggerPresenceForLeakReporting} {$define FastMM_RequireDebuggerPresenceForLeakReporting} {$endif}
{$ifdef NoMessageBoxes} {$define FastMM_NoMessageBoxes} {$endif}
{$ifdef ShareMM} {$define FastMM_ShareMM} {$endif}
{$ifdef ShareMM} {$define FastMM_ShareMMIfLibrary} {$endif}
{$ifdef ShareMM} {$define FastMM_AttemptToUseSharedMM} {$endif}
{$ifdef ShareMM} {$define FastMM_NeverUninstall} {$endif}
{If the "FastMM_FullDebugMode" is defined then a static dependency on the debug support library is assumed, unless
dynamic loading is explicitly specified.}
{$ifdef FastMM_FullDebugMode}
{$ifndef FastMM_DebugLibraryDynamicLoading}
{$define FastMM_DebugLibraryStaticDependency}
{$endif}
{$endif}
{Calling the deprecated GetHeapStatus is unavoidable, so suppress the warning.}
{$warn Symbol_Deprecated Off}
{$warn Symbol_Platform Off}
{$if SizeOf(Pointer) = 8}
{$define 64Bit}
{$else}
{$define 32Bit}
{$endif}
{$ifdef CPUX86}
{$ifndef PurePascal}
{$define X86ASM}
{$endif}
{$else}
{$ifdef CPUX64}
{$ifndef PurePascal}
{$define X64ASM}
{$endif}
{$else}
{x86/x64 CPUs do not reorder writes, but ARM CPUs do.}
{$define WeakMemoryOrdering}
{$define PurePascal}
{$endif}
{$endif}
const
{The current version of FastMM. The first digit is the major version, followed by a two digit minor version number.}
CFastMM_Version = 504;
{The number of arenas for small, medium and large blocks. Increasing the number of arenas decreases the likelihood
of thread contention happening (when the number of threads inside a GetMem call is greater than the number of arenas),
at a slightly higher fixed cost per GetMem call. Usually two threads can be served simultaneously from the same arena
(a new block can be split off for one thread while a freed block can be recycled for the other), so the optimal number
of arenas is usually somewhere between 0.5x and 1x the number of threads. Large block arenas are cheaper in both
performance and memory usage than small and medium block arenas, so typically more large block arenas are used. If
you suspect that thread contention may be dragging down performance, inspect the FastMM_...BlockThreadContentionCount
variables - if their numbers are high then an increase in the number of arenas will reduce thread contention.}
{$if defined(FastMM_16Arenas)}
CFastMM_SmallBlockArenaCount = 16;
CFastMM_MediumBlockArenaCount = 16;
CFastMM_LargeBlockArenaCount = 16;
{$elseif defined(FastMM_15Arenas)}
CFastMM_SmallBlockArenaCount = 15;
CFastMM_MediumBlockArenaCount = 15;
CFastMM_LargeBlockArenaCount = 15;
{$elseif defined(FastMM_14Arenas)}
CFastMM_SmallBlockArenaCount = 14;
CFastMM_MediumBlockArenaCount = 14;
CFastMM_LargeBlockArenaCount = 14;
{$elseif defined(FastMM_13Arenas)}
CFastMM_SmallBlockArenaCount = 13;
CFastMM_MediumBlockArenaCount = 13;
CFastMM_LargeBlockArenaCount = 13;
{$elseif defined(FastMM_12Arenas)}
CFastMM_SmallBlockArenaCount = 12;
CFastMM_MediumBlockArenaCount = 12;
CFastMM_LargeBlockArenaCount = 12;
{$elseif defined(FastMM_11Arenas)}
CFastMM_SmallBlockArenaCount = 11;
CFastMM_MediumBlockArenaCount = 11;
CFastMM_LargeBlockArenaCount = 11;
{$elseif defined(FastMM_10Arenas)}
CFastMM_SmallBlockArenaCount = 10;
CFastMM_MediumBlockArenaCount = 10;
CFastMM_LargeBlockArenaCount = 10;
{$elseif defined(FastMM_9Arenas)}
CFastMM_SmallBlockArenaCount = 9;
CFastMM_MediumBlockArenaCount = 9;
CFastMM_LargeBlockArenaCount = 9;
{$elseif defined(FastMM_8Arenas)}
CFastMM_SmallBlockArenaCount = 8;
CFastMM_MediumBlockArenaCount = 8;
CFastMM_LargeBlockArenaCount = 8;
{$elseif defined(FastMM_7Arenas)}
CFastMM_SmallBlockArenaCount = 7;
CFastMM_MediumBlockArenaCount = 7;
CFastMM_LargeBlockArenaCount = 8;
{$elseif defined(FastMM_6Arenas)}
CFastMM_SmallBlockArenaCount = 6;
CFastMM_MediumBlockArenaCount = 6;
CFastMM_LargeBlockArenaCount = 8;
{$elseif defined(FastMM_5Arenas)}
CFastMM_SmallBlockArenaCount = 5;
CFastMM_MediumBlockArenaCount = 5;
CFastMM_LargeBlockArenaCount = 8;
{$else}
{Default values - typically performs fine up to 8 simultaneous threads.}
CFastMM_SmallBlockArenaCount = 4;
CFastMM_MediumBlockArenaCount = 4;
CFastMM_LargeBlockArenaCount = 8;
{$endif}
{The default name of debug support library.}
CFastMM_DefaultDebugSupportLibraryName = {$ifndef 64Bit}'FastMM_FullDebugMode.dll'{$else}'FastMM_FullDebugMode64.dll'{$endif};
type
{The optimization strategy for the memory manager.}
TFastMM_MemoryManagerOptimizationStrategy = (mmosOptimizeForSpeed, mmosBalanced, mmosOptimizeForLowMemoryUsage);
TFastMM_MemoryManagerEventType = (
{Another third party memory manager has already been installed.}
mmetAnotherThirdPartyMemoryManagerAlreadyInstalled,
{FastMM cannot be installed, because memory has already been allocated through the default memory manager.}
mmetCannotInstallAfterDefaultMemoryManagerHasBeenUsed,
{When an attempt is made to install or use a shared memory manager, but the memory manager has already been used to
allocate memory.}
mmetCannotSwitchToSharedMemoryManagerWithLivePointers,
{Details about an individual memory leak.}
mmetUnexpectedMemoryLeakDetail,
{Summary of memory leaks}
mmetUnexpectedMemoryLeakSummary,
{When an attempt to free or reallocate a debug block that has already been freed is detected.}
mmetDebugBlockDoubleFree,
mmetDebugBlockReallocOfFreedBlock,
{When a corruption of the memory pool is detected.}
mmetDebugBlockHeaderCorruption,
mmetDebugBlockFooterCorruption,
mmetDebugBlockModifiedAfterFree,
{When a virtual method is called on a freed object.}
mmetVirtualMethodCallOnFreedObject);
TFastMM_MemoryManagerEventTypeSet = set of TFastMM_MemoryManagerEventType;
TFastMM_MemoryManagerInstallationState = (
{The default memory manager is currently in use.}
mmisDefaultMemoryManagerInUse,
{Another third party memory manager has been installed.}
mmisOtherThirdPartyMemoryManagerInstalled,
{A shared memory manager is being used.}
mmisUsingSharedMemoryManager,
{This memory manager has been installed.}
mmisInstalled);
{The debug block header. Must be a multiple of 64 in order to guarantee that minimum block alignment restrictions
are honoured.}
{$PointerMath On}
PFastMM_DebugBlockHeader = ^TFastMM_DebugBlockHeader;
{$PointerMath Off}
TFastMM_DebugBlockHeader = packed record
{The first two pointer sized slots cannot be used by the debug block header. The medium block manager uses the
first two pointers in a free block for the free block linked list, and the small block manager uses the first
pointer for the free block linked list. This space is thus reserved.}
Reserved1: Pointer;
Reserved2: Pointer;
{Reserved space for future use.}
{$ifdef 32Bit}
ReservedSpace1: array[0..23] of Byte;
{$else}
ReservedSpace1: array[0..7] of Byte;
{$endif}
{The xor of all subsequent dwords in this structure.}
HeaderCheckSum: Cardinal;
{The allocation number: All debug mode allocations are numbered sequentially. This number may be useful in memory
leak analysis. If it reaches 4G it wraps back to 0.}
AllocationNumber: Cardinal;
{The user requested size for the block.}
UserSize: NativeInt;
{The object class this block was used for the previous time it was allocated. When a block is freed, the pointer
that would normally be in the space of the class pointer is copied here, so if it is detected that the block was
used after being freed we have an idea what class it is.}
PreviouslyUsedByClass: Pointer;
{The value of the FastMM_CurrentAllocationGroup when the block was allocated. Can be used in the debugging process
to group related memory leaks together.}
AllocationGroup: Cardinal;
{The ID of the thread that allocated the block}
AllocatedByThread: Cardinal;
{The ID of the thread that freed the block}
FreedByThread: Cardinal;
{Reserved space for future use.}
ReservedSpace2: Byte;
{The number of entries in the allocation and free call stacks in the debug footer.}
StackTraceEntryCount: Byte;
{The debug block signature. This will always be CIsDebugBlockFlag.}
DebugBlockFlags: SmallInt;
{Returns a pointer to the start of the debug footer. The debug footer consists of the footer checksum (dword),
followed by the allocation stack trace and then the free stack trace.}
function DebugFooterPtr: PCardinal; inline;
{Returns a pointer to the first entry in the allocation stack trace in the debug footer.}
function DebugFooter_AllocationStackTracePtr: PNativeUInt; inline;
{Returns a pointer to the first entry in the free stack trace in the debug footer.}
function DebugFooter_FreeStackTracePtr: PNativeUInt; inline;
{Calculate the header checksum}
function CalculateHeaderCheckSum: Cardinal;
{Calculate the checksum for the stack traces that follow after the user data.}
function CalculateFooterCheckSum: Cardinal;
{Calculates and sets both the header and footer checksums.}
procedure CalculateAndSetHeaderAndFooterCheckSums;
end;
TFastMM_WalkAllocatedBlocksBlockType = (
btLargeBlock,
btMediumBlockSpan,
btMediumBlock,
btSmallBlockSpan,
btSmallBlock);
TFastMM_WalkBlocksBlockTypes = set of TFastMM_WalkAllocatedBlocksBlockType;
TFastMM_WalkAllocatedBlocks_BlockInfo = record
BlockAddress: Pointer;
{If there is additional debug information for the block, this will be a pointer to it. (Will be nil if there is no
additional debug information for the block.}
DebugInformation: PFastMM_DebugBlockHeader;
{The size of the block or span. This includes the size of the block header, padding and internal fragmentation.}
BlockSize: NativeInt;
{The usable size of the block. This is BlockSize less any headers, footers, other management structures and
internal fragmentation.}
UsableSize: NativeInt;
{An arbitrary pointer value passed in to the WalkAllocatedBlocks routine, which is passed through to the callback.}
UserData: Pointer;
{The arena number for the block}
ArenaIndex: Byte;
{The type of block}
BlockType: TFastMM_WalkAllocatedBlocksBlockType;
{True if the block is free, False if it is in use}
BlockIsFree: Boolean;
{--------Medium block spans only-------}
{If True this is the current sequential feed medium block span for ArenaIndex}
IsSequentialFeedMediumBlockSpan: Boolean;
{If this is the sequential feed span for the medium block arena then this will contain the number of bytes
currently unused.}
MediumBlockSequentialFeedSpanUnusedBytes: Integer;
{----Small block spans only-----}
{If True this is the current sequential feed small block span for ArenaIndex and the block size}
IsSequentialFeedSmallBlockSpan: Boolean;
{If IsSmallBlockSpan = True then this will contain the size of the small block.}
SmallBlockSpanBlockSize: Word;
{If this is a sequential feed small block span then this will contain the number of bytes currently unused.}
SmallBlockSequentialFeedSpanUnusedBytes: Integer;
end;
TFastMM_WalkBlocksCallback = procedure(const ABlockInfo: TFastMM_WalkAllocatedBlocks_BlockInfo);
{The enumeration returned by the FastMM_DetectStringData, which is used to determine whether a memory block
potentially contains string data.}
TFastMM_StringDataType = (sdtNotAString, sdtAnsiString, sdtUnicodeString);
TFastMM_MinimumAddressAlignment = (maa8Bytes, maa16Bytes, maa32Bytes, maa64Bytes);
TFastMM_MinimumAddressAlignmentSet = set of TFastMM_MinimumAddressAlignment;
{The formats in which text files (e.g. the event log) may be written. Controlled via the FastMM_TextFileEncoding
variable.}
TFastMM_TextFileEncoding = (
{UTF-8 with no byte-order mark}
teUTF8,
{UTF-8 with a byte-order mark}
teUTF8_BOM,
{UTF-16 little endian, with no byte-order mark}
teUTF16LE,
{UTF-16 little endian, with a byte-order mark}
teUTF16LE_BOM);
{A routine used to obtain the current stack trace up to AMaxDepth levels deep. The first ASkipFrames frames in the
stack trace are skipped. Unused entries will be set to 0.}
TFastMM_GetStackTrace = procedure(APReturnAddresses: PNativeUInt; AMaxDepth, ASkipFrames: Cardinal);
{A routine used to convert a stack trace to a textual representation (typically unit and line information).
APReturnAddresses points to a buffer with up to AMaxDepth return addresses (zero return addresses are ignored). The
textual representation is stored to APBuffer. The routine will return the new end of the buffer.}
TFastMM_ConvertStackTraceToText = function(APReturnAddresses: PNativeUInt; AMaxDepth: Cardinal;
APBuffer, APBufferEnd: PWideChar): PWideChar;
{The interface for the legacy (version 4) stack trace conversion routine in the FastMM_FullDebugMode library.}
TFastMM_LegacyConvertStackTraceToText = function(APReturnAddresses: PNativeUInt; AMaxDepth: Cardinal;
APBuffer: PAnsiChar): PAnsiChar;
{List of registered leaks}
TFastMM_RegisteredMemoryLeak = record
LeakAddress: Pointer;
LeakedClass: TClass;
LeakSize: NativeInt;
LeakCount: Integer;
end;
TFastMM_RegisteredMemoryLeaks = array of TFastMM_RegisteredMemoryLeak;
TFastMM_UsageSummary = record
{The total number of bytes allocated by the application.}
AllocatedBytes: NativeUInt;
{The committed virtual address space less AllocatedBytes: The total number of address space bytes used by control
structures, or lost due to fragmentation and other overhead. Blocks that have been freed by the application but
not yet released back to the operating system are included in this total.}
OverheadBytes: NativeUInt;
{The efficiency of the memory manager expressed as a percentage. This is:
100 * AllocatedBytes / (AllocatedBytes + OverheadBytes).}
EfficiencyPercentage: Double;
end;
{------------------------Core memory manager interface------------------------}
function FastMM_GetMem(ASize: NativeInt): Pointer;
function FastMM_FreeMem(APointer: Pointer): Integer;
function FastMM_ReallocMem(APointer: Pointer; ANewSize: NativeInt): Pointer;
function FastMM_AllocMem(ASize: NativeInt): Pointer;
{------------------------Debug mode core memory manager interface------------------------}
function FastMM_DebugGetMem(ASize: NativeInt): Pointer;
function FastMM_DebugFreeMem(APointer: Pointer): Integer;
function FastMM_DebugReallocMem(APointer: Pointer; ANewSize: NativeInt): Pointer;
function FastMM_DebugAllocMem(ASize: NativeInt): Pointer;
{------------------------Expected memory leak management------------------------}
{Registers expected memory leaks. Returns True on success. The list of leaked blocks is limited, so failure is
possible if the list is full.}
function FastMM_RegisterExpectedMemoryLeak(ALeakedPointer: Pointer): Boolean; overload;
function FastMM_RegisterExpectedMemoryLeak(ALeakedObjectClass: TClass; ACount: Integer = 1): Boolean; overload;
function FastMM_RegisterExpectedMemoryLeak(ALeakedBlockSize: NativeInt; ACount: Integer = 1): Boolean; overload;
{Removes expected memory leaks. Returns True on success.}
function FastMM_UnregisterExpectedMemoryLeak(ALeakedPointer: Pointer): Boolean; overload;
function FastMM_UnregisterExpectedMemoryLeak(ALeakedObjectClass: TClass; ACount: Integer = 1): Boolean; overload;
function FastMM_UnregisterExpectedMemoryLeak(ALeakedBlockSize: NativeInt; ACount: Integer = 1): Boolean; overload;
{Returns a list of all expected memory leaks}
function FastMM_GetRegisteredMemoryLeaks: TFastMM_RegisteredMemoryLeaks;
{------------------------Diagnostics------------------------}
{Returns the user size of the block, normally the number of bytes requested in the original GetMem or ReallocMem call.
Exception: Outside of debug mode the requested size for small and medium blocks is not tracked, and in these instances
the value returned will be the same as the value returned by the FastMM_BlockMaximumUserBytes call.}
function FastMM_BlockCurrentUserBytes(APointer: Pointer): NativeInt;
{Returns the maximum number of bytes that may safely be used by the application for the block starting at APointer.
This will be greater or equal to the size requested in the original GetMem or ReallocMem call. Note that using more
than the value returned by FastMM_BlockCurrentUserBytes is not recommended, since a reallocation request will only move
up to FastMM_BlockCurrentUserBytes bytes.}
function FastMM_BlockMaximumUserBytes(APointer: Pointer): NativeInt;
{Attempts to release all pending free blocks. Returns True if there were no pending frees, or all pending frees could
be released. Returns False if there were locked (currently in use) managers with pending frees.}
function FastMM_ProcessAllPendingFrees: Boolean;
{Walks the block types indicated by the AWalkBlockTypes set, calling ACallBack for each allocated block. If
AWalkBlockTypes = [] then all block types is assumed. Note that pending free blocks are treated as used blocks for the
purpose of the AWalkUsedBlocksOnly parameter. Call FastMM_ProcessAllPendingFrees first in order to process all pending
frees if this is a concern. ALockTimeoutMilliseconds is the maximum number of millseconds that FastMM_WalkBlocks will
wait to acquire a lock on an arena, skipping the arena if it is unable to do so. Returns True if all blocks were walked
successfully, False if one or more arenas were skipped due to a lock timeout.}
function FastMM_WalkBlocks(ACallBack: TFastMM_WalkBlocksCallback; AWalkBlockTypes: TFastMM_WalkBlocksBlockTypes = [];
AWalkUsedBlocksOnly: Boolean = True; AUserData: Pointer = nil; ALockTimeoutMilliseconds: Cardinal = 1000): Boolean;
{Attempts to determine whether APMemoryBlock points to string data. Used by the leak classification code when a block
cannot be identified as a class instance. May also be used inside the FastMM_WalkBlocks callback in order to determine
the content of walked blocks.}
function FastMM_DetectStringData(APMemoryBlock: Pointer; AAvailableSpaceInBlock: NativeInt): TFastMM_StringDataType;
{Attempts to determine whether APointer points to a valid class instance. Returns the class if it does, otherwise nil.
APointer is assumed to point to to at least 4 (32-bit) or 8 (64-bit) readable bytes of memory. This may be used inside
the FastMM_WalkBlocks callback in order to determine the content of walked blocks.}
function FastMM_DetectClassInstance(APointer: Pointer): TClass;
{Walks all debug mode blocks (blocks that were allocated between a FastMM_EnterDebugMode and FastMM_ExitDebugMode call),
checking for corruption of the debug header, footer, and in the case of freed blocks whether the block content was
modified after the block was freed. If a corruption is encountered an error message will be logged and/or displayed
(as per the error logging configuration) and an invalid pointer exception will be raised. This is a function that
always returns True (unless an exception is raised), so may be used in a debug watch to scan blocks every time the
debugger stops on a breakpoint, etc.}
function FastMM_ScanDebugBlocksForCorruption: Boolean;
{Returns the number of bytes of address space that is currently either committed or reserved by FastMM. This includes
the total used by the heap, as well as all internal management structures. This may be restricted via the
FastMM_SetMemoryUsageLimit call.}
function FastMM_GetCurrentMemoryUsage: NativeUInt;
{Returns a THeapStatus structure with information about the current memory usage.}
function FastMM_GetHeapStatus: THeapStatus;
{Returns the number of allocated bytes, the number of overhead bytes (wastage due to management structures and internal
fragmentation), as well as the efficiency percentage. The efficiency percentage is the total allocated bytes divided
by the total address space committed (whether in use or reserved for future use) multiplied by 100. Note that freed
blocks not yet released to the operating system are included in the overhead, which differs from FastMM_GetHeapStatus
that exposes freed blocks in separate fields.}
function FastMM_GetUsageSummary: TFastMM_UsageSummary;
{Writes a log file containing a summary of the memory manager state and a list of allocated blocks grouped by class.
The file will be saved in the encoding specified by FastMM_TextFileEncoding. ALockTimeoutMilliseconds is the maximum
amount of time to wait for a lock on a manager to be released, before it is skipped. Returns True on success.}
function FastMM_LogStateToFile(const AFilename: string; const AAdditionalDetails: string = '';
ALockTimeoutMilliseconds: Cardinal = 1000): Boolean;
{------------------------Memory Manager Sharing------------------------}
{Searches the current process for a shared memory manager. If no memory has been allocated using this memory manager
it will switch to using the shared memory manager instead. Returns True if another memory manager was found and it
could be shared. If this memory manager instance *is* the shared memory manager, it will do nothing and return True.}
function FastMM_AttemptToUseSharedMemoryManager: Boolean;
{Starts sharing this memory manager with other modules in the current process. Only one memory manager may be shared
per process, so this function may fail.}
function FastMM_ShareMemoryManager: Boolean;
{------------------------Configuration------------------------}
{Executes the initialization and finalization code for the memory manager. FastMM_Initialize will run during unit
initialization and FastMM_Finalize during unit finalization, unless "FastMM_DisableAutomaticInstall" is defined. If
"FastMM_DisableAutomaticInstall" is defined then FastMM_Initialize must be called from application code in order to
initialize and install the memory manager, and FastMM_Finalize must be called to uninstall it and perform leak checks,
etc. Note that FastMM cannot be installed if another third party memory manager has already been installed, or if
memory has already been allocated through the default memory manager. FastMM_Initialize will return True on successful
installation, False otherwise. FastMM_Finalize will return True if FastMM_Initialize was previously called, False
otherwise.}
function FastMM_Initialize: Boolean;
function FastMM_Finalize: Boolean;
{Returns the current installation state of the memory manager.}
function FastMM_GetInstallationState: TFastMM_MemoryManagerInstallationState;
{Gets/sets the optimization strategy for the memory manager. FastMM can be optimized for maximum performance, low
memory usage or a blend of the two.}
procedure FastMM_SetOptimizationStrategy(AStrategy: TFastMM_MemoryManagerOptimizationStrategy);
function FastMM_GetCurrentOptimizationStrategy: TFastMM_MemoryManagerOptimizationStrategy;
{Call FastMM_EnterMinimumAddressAlignment to request that all subsequent allocated blocks are aligned to the specified
minimum. Call FastMM_ExitMinimumAddressAlignment to rescind a prior request. Requests for coarser alignments have
precedence over requests for lesser alignments. These calls are thread safe. In the current implementation the
following minimum alignments are always in effect, regardless of any alignment requests:
32-Bit applications: >= maa8Bytes
64-bit applications: >= maa16Bytes
Allocations greater than 150 bytes: >= maa16Bytes
Allocations greater than 302 bytes: >= maa32Bytes
Allocations greater than 606 bytes: maa64Bytes}
procedure FastMM_EnterMinimumAddressAlignment(AMinimumAddressAlignment: TFastMM_MinimumAddressAlignment);
procedure FastMM_ExitMinimumAddressAlignment(AMinimumAddressAlignment: TFastMM_MinimumAddressAlignment);
{Returns the current minimum address alignment in effect.}
function FastMM_GetCurrentMinimumAddressAlignment: TFastMM_MinimumAddressAlignment;
{Allows the application to specify a maximum amount of memory that may be allocated through FastMM. An attempt to
allocate more than this amount will fail and lead to an "Out of Memory" exception. Note that after the first failure
the maximum amount of memory that may be allocated is slightly increased in order to allow the application to allocate
some additional memory in subsequent attempts. This is to allow for a graceful shutdown. Specify 0 for no limit (the
default).}
procedure FastMM_SetMemoryUsageLimit(AMaximumAllowedMemoryUsage: NativeUInt);
function FastMM_GetMemoryUsageLimit: NativeUInt;
{Attempts to load the debug support library specified by FastMM_DebugSupportLibraryName. On success it will set the
FastMM_GetStackTrace and FastMM_ConvertStackTraceToText handlers to point to the routines in the debug library, provided
alternate handlers have not yet been assigned by the application. Returns True if the library was loaded successfully,
or was already loaded successfully prior to this call. FastMM_EnterDebugMode will call FastMM_LoadDebugSupportLibrary
the first time it is called, unless the debug support library has already been loaded or handlers for both
FastMM_GetStackTrace and FastMM_ConvertStackTraceToText have been set by the application.}
function FastMM_LoadDebugSupportLibrary: Boolean;
{Frees the debug support library, pointing the stack trace handlers currently using the debug support library back to
the default no-op handlers.}
function FastMM_FreeDebugSupportLibrary: Boolean;
{Enters/exits debug mode. Calls may be nested, in which case debug mode is only exited when the number of
FastMM_ExitDebugMode calls equal the number of FastMM_EnterDebugMode calls. In debug mode extra metadata is logged
before and after the user data in the block, and extra checks are performed in order to catch common programming
errors. Returns True on success, False if this memory manager instance is not currently installed or the installed
memory manager has changed. Note that debug mode comes with a severe performance penalty, and due to the extra
metadata all blocks that are allocated while debug mode is active will use significantly more address space.}
function FastMM_EnterDebugMode: Boolean;
function FastMM_ExitDebugMode: Boolean;
{Returns True if debug mode is currently active, i.e. FastMM_EnterDebugMode has been called more times than
FastMM_ExitDebugMode.}
function FastMM_DebugModeActive: Boolean;
{Enables/disables the erasure of the content of freed blocks. Calls may be nested, in which case erasure is only
disabled when the number of FastMM_EndEraseFreedBlockContent calls equal the number of
FastMM_BeginEraseFreedBlockContent calls. When enabled the content of all freed blocks is filled with the debug pattern
$80808080 before being returned to the memory pool. This is useful for security purposes, and may also help catch "use
after free" programming errors (like debug mode, but at reduced CPU cost).}
function FastMM_BeginEraseFreedBlockContent: Boolean;
function FastMM_EndEraseFreedBlockContent: Boolean;
{Returns True if free blocks are currently erased on free, i.e. FastMM_BeginEraseFreedBlockContent has been called more
times than FastMM_EndEraseFreedBlockContent.}
function FastMM_EraseFreedBlockContentActive: Boolean;
{Gets/sets the depth of allocation and free stack traces in debug mode. The minimum stack trace depth is 0, and the
maximum is CFastMM_MaximumStackTraceEntryCount.}
function FastMM_GetDebugModeStackTraceEntryCount: Byte;
procedure FastMM_SetDebugModeStackTraceEntryCount(AStackTraceEntryCount: Byte);
{No-op call stack routines.}
procedure FastMM_NoOpGetStackTrace(APReturnAddresses: PNativeUInt; AMaxDepth, ASkipFrames: Cardinal);
function FastMM_NoOpConvertStackTraceToText(APReturnAddresses: PNativeUInt; AMaxDepth: Cardinal;
APBufferPosition, APBufferEnd: PWideChar): PWideChar;
{Sets the default event log path and filename. If the FastMMLogFilePath environment variable is set then that will be
used as the path, otherwise the path to the application will be used. The filename is built from the name of the
application.}
procedure FastMM_SetDefaultEventLogFilename;
{Sets the full path and filename for the event log. if APEventLogFilename = nil then the default event log filename
will be set.}
procedure FastMM_SetEventLogFilename(APEventLogFilename: PWideChar);
{Returns the current full path and filename for the event log.}
function FastMM_GetEventLogFilename: PWideChar;
{Deletes the event log file.}
function FastMM_DeleteEventLogFile: Boolean;
var
{-----------Stack trace support routines----------}
{The active routines used to get a call stack and to convert it to a textual representation. These will be set to
the no-op routines during startup. If either of these have not been assigned a different value when
FastMM_EnterDebugMode is called for the first time then an attempt will be made to load the debug support DLL and
any of these still set to the no-op routines will be rerouted to the handlers in the debug support DLL.}
FastMM_GetStackTrace: TFastMM_GetStackTrace;
FastMM_ConvertStackTraceToText: TFastMM_ConvertStackTraceToText;
{---------Debug options---------}
{The name of the library that contains the functionality used to obtain the current call stack, and also to convert a
call stack to unit and line number information. The first time EnterDebugMode is called an attempt will be made to
load this library, unless handlers for both FastMM_GetStackTrace and FastMM_ConvertStackTraceToText have already been
set.}
FastMM_DebugSupportLibraryName: PWideChar = CFastMM_DefaultDebugSupportLibraryName;
{If True then FastMM will not be finalized and uninstalled when this unit is finalized. Use this option when for some
reason there are live pointers that will still be in use after this unit is finalized. Under normal operation this
should not be necessary.}
FastMM_NeverUninstall: Boolean = False;
{Allocates all memory from the top of the address space downward. This is useful to catch bad pointer typecasts in
64-bit code, where pointers would otherwise often fit in a 32-bit variable. Note that this comes with a performance
impact in the other of O(n^2), where n is the number of chunks obtained from the OS.}
FastMM_AllocateTopDown: Boolean = False;
{When this variable is True and debug mode is enabled, all debug blocks will be checked for corruption on entry to any
memory manager operation (i.e. GetMem, FreeMem, AllocMem and ReallocMem). Note that this comes with an extreme
performance penalty.}
FastMM_DebugMode_ScanForCorruptionBeforeEveryOperation: Boolean = False;
{The events that are passed to OutputDebugString.}
FastMM_OutputDebugStringEvents: TFastMM_MemoryManagerEventTypeSet = [mmetDebugBlockDoubleFree,
mmetDebugBlockReallocOfFreedBlock, mmetDebugBlockHeaderCorruption, mmetDebugBlockFooterCorruption,
mmetDebugBlockModifiedAfterFree, mmetVirtualMethodCallOnFreedObject, mmetAnotherThirdPartyMemoryManagerAlreadyInstalled,
mmetCannotInstallAfterDefaultMemoryManagerHasBeenUsed, mmetCannotSwitchToSharedMemoryManagerWithLivePointers];
{The events that are logged to file.}
FastMM_LogToFileEvents: TFastMM_MemoryManagerEventTypeSet = [mmetDebugBlockDoubleFree,
mmetDebugBlockReallocOfFreedBlock, mmetDebugBlockHeaderCorruption, mmetDebugBlockFooterCorruption,
mmetDebugBlockModifiedAfterFree, mmetVirtualMethodCallOnFreedObject, mmetAnotherThirdPartyMemoryManagerAlreadyInstalled,
mmetCannotInstallAfterDefaultMemoryManagerHasBeenUsed, mmetCannotSwitchToSharedMemoryManagerWithLivePointers];
{The events that are displayed in a message box.}
FastMM_MessageBoxEvents: TFastMM_MemoryManagerEventTypeSet = [mmetDebugBlockDoubleFree,
mmetDebugBlockReallocOfFreedBlock, mmetDebugBlockHeaderCorruption, mmetDebugBlockFooterCorruption,
mmetDebugBlockModifiedAfterFree, mmetVirtualMethodCallOnFreedObject, mmetAnotherThirdPartyMemoryManagerAlreadyInstalled,
mmetCannotInstallAfterDefaultMemoryManagerHasBeenUsed, mmetCannotSwitchToSharedMemoryManagerWithLivePointers];
{All debug blocks are tagged with the current value of this variable when the block is allocated. This may be used
by the application to track memory issues.}
FastMM_CurrentAllocationGroup: Cardinal;
{This variable is incremented during every debug getmem call (wrapping to 0 once it hits 4G) and stored in the debug
header. It may be useful for debugging purposes.}
FastMM_LastAllocationNumber: Cardinal;
{These variables are incremented every time all the arenas for the block size are locked simultaneously and FastMM had
to relinquish the thread's timeslice during a GetMem or ReallocMem call. (FreeMem frees can always be deferred, so
will never cause a thread contention). If these numbers are excessively high then it is an indication that the number
of small, medium and/or large block arenas are insufficient for the number of application threads and should be
increased. (The CFastMM_SmallBlockArenaCount, CFastMM_MediumBlockArenaCount and CFastMM_LargeBlockArenaCount constants.)}
FastMM_SmallBlockThreadContentionCount: Cardinal;
FastMM_MediumBlockThreadContentionCount: Cardinal;
FastMM_LargeBlockThreadContentionCount: Cardinal;
{---------Message and log file text configuration--------}
{The text encoding to use for the event log and other text file output.}
FastMM_TextFileEncoding: TFastMM_TextFileEncoding;
{Messages contain numeric tokens that will be substituted. The available tokens are:
0: A blank string (invalid token IDs will also translate to this)
1: The current date in yyyy-mm-dd format.
2: The current time in HH:nn:ss format.
3: Block size in bytes
4: The ID of the allocating thread (in hexadecimal).
5: The ID of the freeing thread (in hexadecimal).
6: The stack trace when the block was allocated.
7: The stack trace when the block was freed.
8: The object class for the block. For freed blocks this will be the prior object class, otherwise it will be the
current object class.
9: The allocation number for the block (in decimal).
10: Hex and ASCII dump size in bytes
11: Block address (in hexadecimal).
12: Hex dump of block (each line is followed by #13#10)
13: ASCII dump of block (each line is followed by #13#10)
14: Leak summary entries
15: The size and offsets for modifications to a block after it was freed.
16: The full path and filename of the event log.
17: The virtual method name for a virtual method calls on a freed object
18: The total kilobytes allocated (FastMM_LogStateToFile)
19: The total kilobytes overhead (FastMM_LogStateToFile)
20: The efficiency percentage (FastMM_LogStateToFile)
21: The total number of bytes used by the class (FastMM_LogStateToFile)
22: The number of instances of the class (FastMM_LogStateToFile)
23: The average number of bytes per instance for the class (FastMM_LogStateToFile)
24: The stack trace for a virtual method call on a freed object
}
{This entry precedes every entry in the event log.}
FastMM_LogFileEntryHeader: PWideChar = '--------------------------------{1} {2}--------------------------------'#13#10;
{Memory manager installation errors}
FastMM_CannotInstallAfterDefaultMemoryManagerHasBeenUsedMessage: PWideChar = 'FastMM cannot be installed, because the '
+ 'default memory manager has already been used to allocate memory.';
FastMM_CannotSwitchToSharedMemoryManagerWithLivePointersMessage: PWideChar = 'Cannot switch to the shared memory '
+ 'manager, because the local memory manager instance has already been used to allocate memory.';
FastMM_AnotherMemoryManagerAlreadyInstalledMessage: PWideChar = 'FastMM cannot be installed, because another third '
+ 'party memory manager has already been installed.';
FastMM_CannotSwitchMemoryManagerMessageBoxCaption: PWideChar = 'Cannot Switch Memory Managers';
{Memory leak messages.}
FastMM_MemoryLeakDetailMessage_NormalBlock: PWideChar = 'A memory block has been leaked. The size is: {3}'#13#10#13#10
+ 'The block is currently used for an object of class: {8}'#13#10#13#10
+ 'Current memory dump of {10} bytes starting at pointer address {11}:'#13#10
+ '{12}'#13#10'{13}'#13#10;
FastMM_MemoryLeakDetailMessage_DebugBlock: PWideChar = 'A memory block has been leaked. The size is: {3}'#13#10#13#10
+ 'This block was allocated by thread 0x{4}, and the stack trace (return addresses) at the time was:'
+ '{6}'#13#10#13#10'The block is currently used for an object of class: {8}'#13#10#13#10
+ 'The allocation number is: {9}'#13#10#13#10
+ 'Current memory dump of {10} bytes starting at pointer address {11}:'#13#10
+ '{12}'#13#10'{13}'#13#10;
FastMM_MemoryLeakSummaryMessage_LeakDetailNotLogged: PWideChar = 'This application has leaked memory. '
+ 'The leaks ordered by size are:'#13#10'{14}'#13#10;
FastMM_MemoryLeakSummaryMessage_LeakDetailLoggedToEventLog: PWideChar = 'This application has leaked memory. '
+ 'The leaks ordered by size are:'#13#10'{14}'#13#10#13#10
+ 'Memory leak detail was logged to {16}'#13#10;
FastMM_MemoryLeakMessageBoxCaption: PWideChar = 'Unexpected Memory Leak';
{Attempts to free or reallocate a debug block that has alredy been freed.}
FastMM_DebugBlockDoubleFree: PWideChar = 'An attempt was made to free a block that has already been freed.'#13#10#13#10
+ 'The block size is {3}.'#13#10#13#10
+ 'The block was allocated by thread 0x{4}, and the stack trace (return addresses) at the time was:'
+ '{6}'#13#10#13#10'This block was freed by thread 0x{5}, and the stack trace (return addresses) at the time was:'
+ '{7}'#13#10#13#10
+ 'The allocation number is: {9}'#13#10;
FastMM_DebugBlockReallocOfFreedBlock: PWideChar = 'An attempt was made to resize a block that has already been freed.'#13#10#13#10
+ 'The block size is {3}.'#13#10#13#10
+ 'The block was allocated by thread 0x{4}, and the stack trace (return addresses) at the time was:'
+ '{6}'#13#10#13#10'This block was freed by thread 0x{5}, and the stack trace (return addresses) at the time was:'
+ '{7}'#13#10#13#10
+ 'The allocation number is: {9}'#13#10;
{Memory pool corruption messages.}
FastMM_BlockModifiedAfterFreeMessage: PWideChar = 'A memory block was modified after it was freed.'#13#10#13#10
+ 'The block size is {3}.'#13#10#13#10
+ 'Modifications were detected at offsets (with lengths in brackets): {15}.'#13#10#13#10
+ 'The block was allocated by thread 0x{4}, and the stack trace (return addresses) at the time was:'
+ '{6}'#13#10#13#10'This block was freed by thread 0x{5}, and the stack trace (return addresses) at the time was:'
+ '{7}'#13#10#13#10
+ 'The allocation number is: {9}'#13#10#13#10
+ 'Current memory dump of {10} bytes starting at pointer address {11}:'#13#10
+ '{12}'#13#10'{13}'#13#10;
FastMM_BlockHeaderCorruptedMessage: PWideChar = 'A memory block header has been corrupted.'#13#10#13#10
+ 'Current memory dump of {10} bytes starting at pointer address {11}:'#13#10
+ '{12}'#13#10'{13}'#13#10;
FastMM_BlockFooterCorruptedMessage_AllocatedBlock: PWideChar = 'A memory block footer has been corrupted.'#13#10#13#10
+ 'The block size is {3}.'#13#10#13#10
+ 'The block was allocated by thread 0x{4}, and the stack trace (return addresses) at the time was:'
+ '{6}'#13#10#13#10
+ 'The allocation number is: {9}'#13#10#13#10
+ 'Current memory dump of {10} bytes starting at pointer address {11}:'#13#10
+ '{12}'#13#10'{13}'#13#10;
FastMM_BlockFooterCorruptedMessage_FreedBlock: PWideChar = 'A memory block footer has been corrupted.'#13#10#13#10
+ 'The block size is {3}.'#13#10#13#10
+ 'The block was allocated by thread 0x{4}, and the stack trace (return addresses) at the time was:'
+ '{6}'#13#10#13#10'This block was freed by thread 0x{5}, and the stack trace (return addresses) at the time was:'
+ '{7}'#13#10#13#10
+ 'The allocation number is: {9}'#13#10#13#10
+ 'Current memory dump of {10} bytes starting at pointer address {11}:'#13#10
+ '{12}'#13#10'{13}'#13#10;
FastMM_MemoryCorruptionMessageBoxCaption: PWideChar = 'Memory Corruption Detected';
{Virtual method call on a freed object.}
FastMM_VirtualMethodCallOnFreedObjectMessage: PWideChar = 'A virtual method was called on a freed object.'#13#10#13#10
+ 'Freed object class: {8}'#13#10#13#10
+ 'Virtual method: {17}'#13#10#13#10
+ 'The block size is {3}.'#13#10#13#10
+ 'The block was allocated by thread 0x{4}, and the stack trace (return addresses) at the time was:'
+ '{6}'#13#10#13#10'This block was freed by thread 0x{5}, and the stack trace (return addresses) at the time was:'
+ '{7}'#13#10#13#10'The stack trace for the virtual call that lead to this error is:'
+ '{24}'#13#10#13#10
+ 'The allocation number is: {9}'#13#10#13#10
+ 'Current memory dump of {10} bytes starting at pointer address {11}:'#13#10
+ '{12}'#13#10'{13}'#13#10;
FastMM_VirtualMethodCallOnFreedObjectMessageBoxCaption: PWideChar = 'Virtual Method Call On Freed Object';
{Memory state logging messages}
FastMM_LogStateToFileTemplate: PWideChar = 'FastMM State Capture:'#13#10
+ '---------------------'#13#10
+ '{18}K Allocated'#13#10
+ '{19}K Overhead'#13#10
+ '{20}% Efficiency'#13#10#13#10
+ 'Usage Detail:'#13#10;
FastMM_LogStateToFileTemplate_UsageDetail: PWideChar = '{21} bytes: {8} x {22} ({23} bytes avg.)'#13#10;
{$ifndef FastMM_DebugLibraryStaticDependency}
{The stack trace routines from the FastMM_FullDebugMode support DLL. These will only be set if the support DLL is
loaded.}
DebugLibrary_GetRawStackTrace: TFastMM_GetStackTrace;
DebugLibrary_GetFrameBasedStackTrace: TFastMM_GetStackTrace;
{The legacy stack trace to text conversion routine from the FastMM_FullDebugMode support DLL. This will only be set
if the support DLL is loaded. This is used by the FastMM_DebugLibrary_LegacyLogStackTrace_Wrapper function.}
DebugLibrary_LogStackTrace_Legacy: TFastMM_LegacyConvertStackTraceToText;
{$else}
procedure DebugLibrary_GetRawStackTrace(APReturnAddresses: PNativeUInt; AMaxDepth, ASkipFrames: Cardinal);
external CFastMM_DefaultDebugSupportLibraryName name 'GetRawStackTrace';
procedure DebugLibrary_GetFrameBasedStackTrace(APReturnAddresses: PNativeUInt; AMaxDepth, ASkipFrames: Cardinal);
external CFastMM_DefaultDebugSupportLibraryName name 'GetFrameBasedStackTrace';
function DebugLibrary_LogStackTrace_Legacy(APReturnAddresses: PNativeUInt; AMaxDepth: Cardinal;
APBuffer: PAnsiChar): PAnsiChar; external CFastMM_DefaultDebugSupportLibraryName name 'LogStackTrace';
{$endif}
implementation
{All blocks are preceded by a block header. The block header varies in size according to the block type. The block
type and state may be determined from the bits of the word preceding the block address, as follows:
All block types:
----------------
Bit 0: Block is free flag
0 = Block is in use
1 = Block is free
Bit 1: Debug info flag
0 = the block contains no additional debug information
1 = the block contains a debug mode sub-block
Bit 2: Block type 1
0 = Is not a small block
1 = Is a small block
Small blocks only (bit 2 = 1):
------------------------------
Bits 3..15: Offset to small block span header
The offset of the block from the start of the small block span header, divided by 64.
Medium, Large and Debug Blocks (bit 2 = 0):
-------------------------------------------
Bit 3: Block type 2
0 = Is not a medium block
1 = Is a medium block
Bit 4: Block type 3
0 = Is not a large block
1 = Is a large block
Bit 5: Block type 4
0 = Is not a debug sub-block
1 = Is a debug sub-block
Bits 6..15: Reserved (always 0)
}
const
{$ifdef 32Bit}
CPointerSizeBitShift = 2; //1 shl 2 = 4
CTObjectInstanceSize = 8;
{$else}
CPointerSizeBitShift = 3; //1 shl 3 = 8
CTObjectInstanceSize = 16;
{$endif}
{Block status flags}
CBlockIsFreeFlag = 1;
CHasDebugInfoFlag = 2;
CIsSmallBlockFlag = 4;
CIsMediumBlockFlag = 8;
CIsLargeBlockFlag = 16;
CIsDebugBlockFlag = 32;
{-----Small block constants-----}
{$ifdef 32Bit}
CSmallBlockTypeCount = 61;
CSmallBlockGranularityBits = 3;
{$else}
CSmallBlockTypeCount = 51;
CSmallBlockGranularityBits = 4;
{$endif}
CSmallBlockGranularity = 1 shl CSmallBlockGranularityBits;
CMaximumSmallBlockSize = 2624; //Must be a multiple of 64 for the 64-byte alignment option to work
CSmallBlockFlagCount = 3;
CDropSmallBlockFlagsMask = - (1 shl CSmallBlockFlagCount);
CSmallBlockSpanOffsetBitShift = 6 - CSmallBlockFlagCount;
{-----Medium block constants-----}
{Medium blocks are always aligned to at least 64 bytes (which is the typical cache line size). Spans must be a
multiple of 64K (to make optimal use of the virtual address space), and offsets divided by the granularity must fit
inside a 16-bit word.}
CMediumBlockAlignmentBits = 6;
CMediumBlockAlignment = 1 shl CMediumBlockAlignmentBits;
CMaximumMediumBlockSpanSize = 64 * 1024 * CMediumBlockAlignment; // = 4MB
{Medium blocks are binned in linked lists - one linked list for each size.}
CMediumBlockBinsPerGroup = 32;
CMediumBlockBinGroupCount = 32;
CMediumBlockBinCount = CMediumBlockBinGroupCount * CMediumBlockBinsPerGroup;
{The smallest medium block should be <= 10% greater than the largest small block. It is an odd multiple
of the typical cache line size in order to facilitate better cache line utilization.}
CMinimumMediumBlockSize = CMaximumSmallBlockSize + 256; // = 2880
{The spacing between medium block bins is not constant. There are three groups: initial, middle and final.}
CInitialBinCount = 384;
CInitialBinSpacingBits = 8;
CInitialBinSpacing = 1 shl CInitialBinSpacingBits; // = 256
CMediumBlockMiddleBinsStart = CMinimumMediumBlockSize + CInitialBinSpacing * CInitialBinCount;
CMiddleBinCount = 384;
CMiddleBinSpacingBits = 9;
CMiddleBinSpacing = 1 shl CMiddleBinSpacingBits; // = 512
CMediumBlockFinalBinsStart = CMediumBlockMiddleBinsStart + CMiddleBinSpacing * CMiddleBinCount;
CFinalBinCount = CMediumBlockBinCount - CMiddleBinCount - CInitialBinCount;
CFinalBinSpacingBits = 10;
CFinalBinSpacing = 1 shl CFinalBinSpacingBits; // = 1024
{The maximum size allocatable through medium blocks. Blocks larger than this are allocated via the OS from the
virtual memory pool ( = large blocks).}
CMaximumMediumBlockSize = CMediumBlockFinalBinsStart + (CFinalBinCount - 1) * CFinalBinSpacing;
{-----Large block constants-----}
CLargeBlockGranularity = 64 * 1024; //Address space obtained from VirtualAlloc is always aligned to a 64K boundary
{-----Small block span constants-----}
{Allocating and deallocating small block spans are expensive, so it is not something that should be done frequently.}
CMinimumSmallBlocksPerSpan = 16;
COptimalSmallBlocksPerSpan = 64;
COptimalSmallBlockSpanSizeLowerLimit = CMinimumMediumBlockSize + 16 * 1024;
COptimalSmallBlockSpanSizeUpperLimit = CMinimumMediumBlockSize + 96 * 1024;
{The maximum amount by which a small block span may exceed the optimal size before the block will be split instead of
using it as-is.}
CSmallBlockSpanMaximumAmountWithWhichOptimalSizeMayBeExceeded = 4 * 1024;