UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
MallocDebug.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "CoreTypes.h"
7#include "CoreGlobals.h"
8
9class FOutputDevice;
10
11// Debug memory allocator.
12class FMallocDebug : public FMalloc
13{
14 // Tags.
15 enum { MEM_PreTag = 0xf0ed1cee };
16 enum { MEM_PostTag = 0xdeadf00f };
17 enum { MEM_Tag = 0xfe };
18 enum { MEM_WipeTag = 0xcd };
19
20 // Alignment.
21 enum { ALLOCATION_ALIGNMENT = 16 };
22
23 // Number of block sizes to collate (in steps of 4 bytes)
24 enum { MEM_SizeMax = 128 };
25 enum { MEM_Recent = 5000 };
26 enum { MEM_AgeMax = 80 };
27 enum { MEM_AgeSlice = 100 };
28
29private:
30 // Structure for memory debugging.
31 struct FMemDebug
32 {
34 int32 RefCount;
35 int32* PreTag;
36 FMemDebug* Next;
37 FMemDebug** PrevLink;
38 };
39
40 FMemDebug* GFirstDebug;
41
43 SIZE_T TotalAllocationSize;
45 SIZE_T TotalWasteSize;
46
47 static constexpr uint32 AllocatorOverhead = sizeof(FMemDebug) + sizeof(FMemDebug*) + sizeof(int32) + ALLOCATION_ALIGNMENT + sizeof(int32);
48
49public:
50 // FMalloc interface.
52 : GFirstDebug( nullptr )
53 , TotalAllocationSize( 0 )
54 , TotalWasteSize( 0 )
55 {}
56
60 virtual void* Malloc( SIZE_T Size, uint32 Alignment ) override
61 {
62 check(Alignment <= ALLOCATION_ALIGNMENT && "Alignment currently unsupported in this allocator");
63 FMemDebug* Ptr = (FMemDebug*)malloc( AllocatorOverhead + Size );
64 check(Ptr);
65 uint8* AlignedPtr = Align( (uint8*) Ptr + sizeof(FMemDebug) + sizeof(FMemDebug*) + sizeof(int32), ALLOCATION_ALIGNMENT );
66 Ptr->RefCount = 1;
67
68 Ptr->Size = Size;
69 Ptr->Next = GFirstDebug;
70 Ptr->PrevLink = &GFirstDebug;
71 Ptr->PreTag = (int32*) (AlignedPtr - sizeof(int32));
72 *Ptr->PreTag = MEM_PreTag;
73 *((FMemDebug**)(AlignedPtr - sizeof(int32) - sizeof(FMemDebug*))) = Ptr;
74 *(int32*)(AlignedPtr+Size) = MEM_PostTag;
75 FMemory::Memset( AlignedPtr, MEM_Tag, Size );
76 if( GFirstDebug )
77 {
78 check(GIsCriticalError||GFirstDebug->PrevLink==&GFirstDebug);
79 GFirstDebug->PrevLink = &Ptr->Next;
80 }
81 GFirstDebug = Ptr;
82 TotalAllocationSize += Size;
83 TotalWasteSize += AllocatorOverhead;
84 check(!(PTRINT(AlignedPtr) & ((PTRINT)0xf)));
85 return AlignedPtr;
86 }
87
91 virtual void* Realloc( void* InPtr, SIZE_T NewSize, uint32 Alignment ) override
92 {
93 if( InPtr && NewSize )
94 {
95 FMemDebug* Ptr = *((FMemDebug**)((uint8*)InPtr - sizeof(int32) - sizeof(FMemDebug*)));
96 check(GIsCriticalError||(Ptr->RefCount==1));
97 void* Result = Malloc( NewSize, Alignment );
98 FMemory::Memcpy( Result, InPtr, FMath::Min<SIZE_T>(Ptr->Size,NewSize) );
99 Free( InPtr );
100 return Result;
101 }
102 else if( InPtr == nullptr )
103 {
104 return Malloc( NewSize, Alignment );
105 }
106 else
107 {
108 Free( InPtr );
109 return nullptr;
110 }
111 }
112
116 virtual void Free( void* InPtr ) override
117 {
118 if( !InPtr )
119 {
120 return;
121 }
122
123 FMemDebug* Ptr = *((FMemDebug**)((uint8*)InPtr - sizeof(int32) - sizeof(FMemDebug*)));
124
125 check(GIsCriticalError||Ptr->RefCount==1);
126 check(GIsCriticalError||*Ptr->PreTag==MEM_PreTag);
127 check(GIsCriticalError||*(int32*)((uint8*)InPtr+Ptr->Size)==MEM_PostTag);
128
129 TotalAllocationSize -= Ptr->Size;
130 TotalWasteSize -= AllocatorOverhead;
131
132 FMemory::Memset( InPtr, MEM_WipeTag, Ptr->Size );
133 Ptr->Size = 0;
134 Ptr->RefCount = 0;
135
136 check(GIsCriticalError||Ptr->PrevLink);
137 check(GIsCriticalError||*Ptr->PrevLink==Ptr);
138 *Ptr->PrevLink = Ptr->Next;
139 if( Ptr->Next )
140 {
141 Ptr->Next->PrevLink = Ptr->PrevLink;
142 }
143
144 free( Ptr );
145 }
146
154 virtual bool GetAllocationSize(void *Original, SIZE_T &SizeOut) override
155 {
156 if( !Original )
157 {
158 SizeOut = 0;
159 }
160 else
161 {
162 const FMemDebug* Ptr = *((FMemDebug**)((uint8*)Original - sizeof(int32) - sizeof(FMemDebug*)));
163 SizeOut = Ptr->Size;
164 }
165
166 return true;
167 }
168
174 virtual void DumpAllocatorStats( FOutputDevice& Ar ) override
175 {
176 Ar.Logf( TEXT( "Total Allocation Size: %u" ), TotalAllocationSize );
177 Ar.Logf( TEXT( "Total Waste Size: %u" ), TotalWasteSize );
178
179 int32 Count = 0;
180 int32 Chunks = 0;
181
182 Ar.Logf( TEXT( "" ) );
183 Ar.Logf( TEXT( "Unfreed memory:" ) );
184 for( FMemDebug* Ptr = GFirstDebug; Ptr; Ptr = Ptr->Next )
185 {
186 Count += (int32)Ptr->Size;
187 Chunks++;
188 }
189
190 Ar.Logf( TEXT( "End of list: %i Bytes still allocated" ), Count );
191 Ar.Logf( TEXT( " %i Chunks allocated" ), Chunks );
192 }
193
197 virtual bool ValidateHeap() override
198 {
199 for( FMemDebug** Link = &GFirstDebug; *Link; Link=&(*Link)->Next )
200 {
201 check(GIsCriticalError||*(*Link)->PrevLink==*Link);
202 }
203#if PLATFORM_WINDOWS
204 int32 Result = _heapchk();
205 check(Result!=_HEAPBADBEGIN);
206 check(Result!=_HEAPBADNODE);
207 check(Result!=_HEAPBADPTR);
208 check(Result!=_HEAPEMPTY);
209 check(Result==_HEAPOK);
210#endif
211 return( true );
212 }
213
214 virtual bool Exec( UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar ) override
215 {
216 return false;
217 }
218
219 virtual const TCHAR* GetDescriptiveName() override { return TEXT("debug"); }
220
221};
constexpr T Align(T Val, uint64 Alignment)
Definition AlignmentTemplates.h:18
#define check(expr)
Definition AssertionMacros.h:314
#define TEXT(x)
Definition Platform.h:1272
FPlatformTypes::SIZE_T SIZE_T
An unsigned integer the same size as a pointer, the same as UPTRINT.
Definition Platform.h:1150
FPlatformTypes::PTRINT PTRINT
A signed integer the same size as a pointer.
Definition Platform.h:1148
FPlatformTypes::TCHAR TCHAR
Either ANSICHAR or WIDECHAR, depending on whether the platform supports wide characters or the requir...
Definition Platform.h:1135
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
uint32 Size
Definition VulkanMemory.cpp:4034
free(DecoderMem)
uint8_t uint8
Definition binka_ue_file_header.h:8
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition MallocDebug.h:13
FMallocDebug()
Definition MallocDebug.h:51
virtual void * Malloc(SIZE_T Size, uint32 Alignment) override
Definition MallocDebug.h:60
virtual bool ValidateHeap() override
Definition MallocDebug.h:197
virtual bool GetAllocationSize(void *Original, SIZE_T &SizeOut) override
Definition MallocDebug.h:154
virtual void * Realloc(void *InPtr, SIZE_T NewSize, uint32 Alignment) override
Definition MallocDebug.h:91
virtual bool Exec(UWorld *InWorld, const TCHAR *Cmd, FOutputDevice &Ar) override
Definition MallocDebug.h:214
virtual void Free(void *InPtr) override
Definition MallocDebug.h:116
virtual void DumpAllocatorStats(FOutputDevice &Ar) override
Definition MallocDebug.h:174
virtual const TCHAR * GetDescriptiveName() override
Definition MallocDebug.h:219
Definition MemoryBase.h:99
Definition OutputDevice.h:133
void Logf(const FmtType &Fmt)
Definition OutputDevice.h:234
Definition World.h:918
static UE_FORCEINLINE_HINT void * Memcpy(void *Dest, const void *Src, SIZE_T Count)
Definition UnrealMemory.h:160
static UE_FORCEINLINE_HINT void * Memset(void *Dest, uint8 Char, SIZE_T Count)
Definition UnrealMemory.h:119