UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
GenericGrowableAllocator.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3/*=============================================================================
4 GrowableAllocator.h: Memory allocator that allocates direct memory for pool memory
5=============================================================================*/
6
7#pragma once
8
9#include "CoreMinimal.h"
11#include "Misc/ScopeLock.h"
13#include "Stats/Stats.h"
14
16// - Don't use a shared CriticalSection, must pass in to the GrowableAllocator
17// - Use this with GPU allocations
18// - search for @todo here and in the SwitchAudioBuffer code
19// - Move this into the FSwitchAudioDevice
20// - Pass this over some code reviews on slack or something for maybe a better way to structure instead of Template and Pure virtual
21// - Can maybe just make virtuals in FGrowableAllocationBase ??
23
24#define ALLOCATION_HISTOGRAM (!UE_BUILD_SHIPPING && !UE_BUILD_TEST) && 1
25#define ALLOCATION_HISTOGRAM_DETAILED (!UE_BUILD_SHIPPING && !UE_BUILD_TEST) && 0
26
28{
32#if !UE_BUILD_SHIPPING
34#endif
35};
36
37// a base class for both the classes below, for usage tracking only
39{
40public:
49 {}
50
55 {
56 double Waste = (static_cast<double>(TotalWaste) / static_cast<double>(TotalAllocs)) * static_cast<double>(CurrentAllocs);
57 return (uint64)Waste;
58 }
59
60protected:
61
64
67
70
73};
74
75
76
78{
79public:
80 // Abstract functions that user must implement
81
91
98 virtual void DestroyInternalMemory() = 0;
99
104
109 {
110 delete Allocation;
111 }
112
118
122 virtual bool DoesChunkContainAllocation(const FGrowableAllocationBase* Allocation) = 0;
123
127 virtual bool DoesChunkContainAddress(const void* Address) = 0;
128
129
141
143 {
144 // create the pool object (note that this will update and return the new HeapSize for the implementations internal aligned size - we then update how big we track)
146 // entire chunk is free
147 FreeList = new FFreeEntry(NULL, 0, HeapSize);
148 MaxFreeEntrySize = FreeList->BlockSize;
149 }
150
155 {
156 }
157
158 void Destroy()
159 {
160 checkf(IsEmpty(), TEXT("Chunk was not empty when it was destroyed!"));
162 }
163
170 bool CanFitEntry(uint32 Size, uint32 Alignment)
171 {
172 // Compute MaxFreeEntrySize if necessary (should only happen if this chunk was just allocated from)
174 {
176 for (FFreeEntry* Entry = FreeList; Entry; Entry = Entry->Next)
177 {
178 MaxFreeEntrySize = FMath::Max(Entry->BlockSize, MaxFreeEntrySize);
179 }
180 }
181
182 // Return false if we trivially don't fit
184 {
185 return false;
186 }
187
188 // Return true if we trivially do fit
189 if (Size + Alignment - 1 <= MaxFreeEntrySize)
190 {
191 return true;
192 }
193
194 // Slow method - search the free entries for a free chunk
195 bool bResult = false;
196 for (FFreeEntry *Entry = FreeList; Entry; Entry = Entry->Next)
197 {
198 if (Entry->CanFit(Size, Alignment))
199 {
200 bResult = true;
201 break;
202 }
203 }
204 return bResult;
205 }
209 bool IsEmpty()
210 {
211 return UsedMemorySize == 0;
212 }
213
214 FGrowableAllocationBase* Malloc(uint32 Size, uint32 Alignment, uint32 MinAllocationSize, int32 OwnerType)
215 {
216 checkSlow(Alignment != 0);
217
218 // multi-thread protection
220
221 // Alignment here is assumed to be for location and size
222 const uint32 AlignedSize = Align<uint32>(Size, Alignment);
223
224 // Update stats.
225 const uint32 WastedSize = AlignedSize - Size;
228 TotalAllocs++;
229
230 // look for a good free chunk
231 FFreeEntry* Prev = NULL;
232 FFreeEntry* FindEntry = NULL;
233
234 for (FFreeEntry* Entry = FreeList; Entry; Entry = Entry->Next)
235 {
236 if (Entry->CanFit(AlignedSize, Alignment))
237 {
238 FindEntry = Entry;
239 break;
240 }
241 Prev = Entry;
242 }
243
244 if (FindEntry != NULL)
245 {
246 if (FindEntry->BlockSize == MaxFreeEntrySize)
247 {
248 // We're probably about to just split our largest entry, so mark the max size as dirty to indicate it needs recomputing
250 }
251 // Use it, leaving over any unused space
252 UsedMemorySize += AlignedSize;
253 bool bDelete;
255 uint32 Offset = FindEntry->Split(AlignedSize, Alignment, bDelete, Padding, MinAllocationSize);
256 if (bDelete)
257 {
258 FFreeEntry*& PrevRef = Prev ? Prev->Next : FreeList;
259 PrevRef = FindEntry->Next;
260 delete FindEntry;
261 }
262
264 Allocation->Size = AlignedSize;
265 Allocation->Padding = Padding;
266 Allocation->Offset = Offset;
267#if !UE_BUILD_SHIPPING
268 Allocation->OwnerType = OwnerType;
269#endif
270 LLM_IF_ENABLED(FLowLevelMemTracker::Get().OnLowLevelAlloc(ELLMTracker::Default, GetAddressForTracking(Offset), Size));
272
273 // let the implementation fill in any more
274 InitializeAllocationStruct(Allocation);
275 return Allocation;
276 }
277
278 // if no suitable blocks were found, we must fail
279 FPlatformMisc::LowLevelOutputDebugStringf(TEXT("Failed to allocate GPU memory (Size: %d)"), AlignedSize);
280 return nullptr;
281 }
282
284 {
285 // multi-thread protection
287
288 uint64 Padding = Memory->Padding;
289 uint64 Size = Memory->Size;
290 uint64 AllocationSize = Padding + Size;
291 uint32 Offset = Memory->Offset;
292
293 LLM_IF_ENABLED(FLowLevelMemTracker::Get().OnLowLevelFree(ELLMTracker::Default, GetAddressForTracking(Offset)));
295
296 // we are now done with the Allocation object
298
301
302 // Search for a place to insert a new free entry
303 FFreeEntry* Prev = NULL;
304 FFreeEntry* Entry = FreeList;
305 while (Entry && Offset > Entry->Location)
306 {
307 Prev = Entry;
308 Entry = Entry->Next;
309 }
310
311 // Are we right before this free entry?
312 if (Entry && (Offset + Size) == Entry->Location)
313 {
314 // Join with chunk
315 Entry->Location -= uint32(AllocationSize);
316 Entry->BlockSize += uint32(AllocationSize);
317
318 // Can we join the two entries?
319 if (Prev && (Prev->Location + Prev->BlockSize) == Entry->Location)
320 {
321 Prev->BlockSize += Entry->BlockSize;
322 Prev->Next = Entry->Next;
323 MaxFreeEntrySize = FMath::Max(MaxFreeEntrySize, Prev->BlockSize);
324 delete Entry;
325 }
326 else
327 {
328 MaxFreeEntrySize = FMath::Max(MaxFreeEntrySize, Entry->BlockSize);
329 }
330 return true;
331 }
332
333 // Are we right after the previous free entry?
334 if (Prev && (Prev->Location + Prev->BlockSize + Padding) == Offset)
335 {
336 // Join with chunk
337 Prev->BlockSize += uint32(AllocationSize);
338
339 // Can we join the two entries?
340 if (Entry && (Prev->Location + Prev->BlockSize) == Entry->Location)
341 {
342 Prev->BlockSize += Entry->BlockSize;
343 Prev->Next = Entry->Next;
344 delete Entry;
345 }
346 MaxFreeEntrySize = FMath::Max(MaxFreeEntrySize, Prev->BlockSize);
347 return true;
348 }
349
350 // Insert a new entry.
351 FFreeEntry* NewFree = new FFreeEntry(Entry, uint32(Offset - Padding), AllocationSize);
352 FFreeEntry*& PrevRef = Prev ? Prev->Next : FreeList;
354 MaxFreeEntrySize = FMath::Max(MaxFreeEntrySize, NewFree->BlockSize);
355 return true;
356 }
357
359 {
360 // @todo: Validate this accounts for alignment padding in the right way
361 Used = UsedMemorySize;
363 }
364
366 {
368
370
371 uint32 Count = 0;
372 uint64 Total = 0;
373
374 FFreeEntry* Entry = FreeList;
375
376 while (Entry)
377 {
378 FPlatformMisc::LowLevelOutputDebugStringf(TEXT(" Location: %d Size: %d\n"), Entry->Location, Entry->BlockSize);
379 if (FreeBlockSizeHistogram.Contains(Entry->BlockSize))
380 {
381 FreeBlockSizeHistogram.FindChecked(Entry->BlockSize)++;
382 }
383 else
384 {
385 FreeBlockSizeHistogram.Add(Entry->BlockSize) = 1;
386 }
387
388 Count++;
389 Total += Entry->BlockSize;
390
391 Entry = Entry->Next;
392 }
393
394 FPlatformMisc::LowLevelOutputDebugStringf(TEXT("Num Blocks: %d Total Size: %d\n"), Count, Total);
395
396 for (auto It = FreeBlockSizeHistogram.CreateIterator(); It; ++It)
397 {
398 FPlatformMisc::LowLevelOutputDebugStringf(TEXT(" %d, %d\n"), It.Key(), It.Value());
399 }
400
401
402 }
403
404 // returns an address usable FOR TRACKING ONLY!
406
407private:
408 class FFreeEntry
409 {
410 public:
412 FFreeEntry(FFreeEntry *NextEntry, uint32 InLocation, uint64 InSize)
413 : Location(InLocation)
414 , BlockSize(uint32(InSize))
415 , Next(NextEntry)
416 {
417 }
418
425 bool CanFit(uint64 AlignedSize, uint32 Alignment)
426 {
427 // location of the aligned allocation
428 uint32 AlignedLocation = Align(Location, Alignment);
429
430 // if we fit even after moving up the location for alignment, then we are good
431 return (AlignedSize + (AlignedLocation - Location)) <= BlockSize;
432 }
433
442 uint32 Split(uint64 UsedSize, uint32 Alignment, bool &bDelete, uint32& Padding, uint32 MinSize)
443 {
444 // make sure we are already aligned
445 check((UsedSize & (Alignment - 1)) == 0);
446
447 // this is the pointer to the free data
448 uint32 FreeLoc = Align(Location, Alignment);
449
450 // Adjust the allocated size for any alignment padding
451 Padding = FreeLoc - Location;
452 uint64 AllocationSize = UsedSize + uint64(Padding);
453
454 // see if there's enough space left over for a new free chunk (of at least a certain size)
455 if (BlockSize - AllocationSize >= MinSize)
456 {
457 // update this free entry to just point to what's left after using the UsedSize
458 Location += uint32(AllocationSize);
459 BlockSize -= uint32(AllocationSize);
460 bDelete = false;
461 }
462 // if no more room, then just remove this entry from the list of free items
463 else
464 {
465 bDelete = true;
466 }
467
468 // return a usable pointer!
469 return FreeLoc;
470 }
471
473 uint32 Location;
474
476 uint32 BlockSize;
477
479 FFreeEntry* Next;
480 };
481
482//protected:
483// @todo make accessors for TGenericGrowableAllocator to call
484public:
485
486 // type of this memory, up to the subclass to define what it means
488
491
494
497
499 FFreeEntry* FreeList;
500
503
504 static const uint32 MaxFreeEntrySizeDirty = 0xffffffff;
505};
506
507
511template <typename ChunkAllocatorType, typename GrowableAllocationBaseType>
513{
514public:
515
524 : SubAllocationAlignment(InSubAllocationAlignment)
525 , MemoryType(InType)
526 , StatRegionName(InStatRegionName)
527 , OwnerTypeToStatIdMap(InOwnerTypeToStatIdMap)
528 , UserData(InUserData)
529 {
530 // create initial chunk
531 if (InitialSize > 0)
532 {
533 CreateAllocChunk(InitialSize);
534 }
535 }
536
537
542 {
543 // remove any existing chunks
544 for (int32 Index = 0; Index < AllocChunks.Num(); Index++)
545 {
546 ChunkAllocatorType* Chunk = AllocChunks[Index];
547 if (Chunk)
548 {
549#if !UE_BUILD_SHIPPING
550 if (!Chunk->IsEmpty())
551 {
552 FPlatformMisc::LowLevelOutputDebugStringf(TEXT("Trying to free a non-empty chunk."));
554 }
555#endif
556
557 RemoveAllocChunk(Chunk);
558 }
559 }
560 }
561
562
564 {
565 // make sure we have some minimal alignment
566 Alignment = FPlatformMath::Max<uint32>(Alignment, SubAllocationAlignment);
567
568 // multi-thread protection
569 FScopeLock ScopeLock(&CriticalSection);
570
572
573 // align the size to match what Malloc does below
574 const uint32 AlignedSize = Align<uint32>(Size, Alignment);
575
576 // Update stats.
577 const uint32 WastedSize = AlignedSize - Size;
581 TotalAllocs++;
582
583 // search for an existing alloc chunk with enough space
584 for (int32 ChunkIndex = 0; ChunkIndex < AllocChunks.Num(); ChunkIndex++)
585 {
586 ChunkAllocatorType* Chunk = AllocChunks[ChunkIndex];
587 if (Chunk && Chunk->CanFitEntry(AlignedSize, Alignment))
588 {
589 AvailableChunk = Chunk;
590 break;
591 }
592 }
593
594 // create a new chunk with enough space + alignment to Switch_GrowableHeapAlignment_MB and allocate out of it
595 if (AvailableChunk == nullptr)
596 {
597 AvailableChunk = CreateAllocChunk(AlignedSize);
598 }
599
600 // allocate from the space in the chunk
601 GrowableAllocationBaseType* Result = nullptr;
602 if (AvailableChunk)
603 {
604 Result = (GrowableAllocationBaseType*)AvailableChunk->Malloc(AlignedSize, Alignment, SubAllocationAlignment, OwnerType);
605 }
606
607 if (AvailableChunk == nullptr || Result == nullptr)
608 {
609 OutOfMemory(AlignedSize);
610 return nullptr;
611 }
612
613#if ALLOCATION_HISTOGRAM
614 TotalAllocationsHistogram.FindOrAdd(AlignedSize)++;
615 PeakAllocationsHistogram.FindOrAdd(AlignedSize)++;
616
617 // track per type allocation info
618 AllocationInfo& TypeAllocInfo = PerTypeAllocationInfo.FindOrAdd(Result->OwnerType);
619
620 TypeAllocInfo.Counts.Allocations++;
621 TypeAllocInfo.TotalAllocated += Result->Size;
622#if ALLOCATION_HISTOGRAM_DETAILED
623 TypeAllocInfo.AllocationHistogram.FindOrAdd(Result->Size).Allocations++;
624#endif
625#endif // ALLOCATION_HISTOGRAM
626
627#if STATS
628 if (OwnerTypeToStatIdMap)
629 {
630 INC_MEMORY_STAT_BY_FName(OwnerTypeToStatIdMap[Result->OwnerType], Result->Size);
631 }
632#endif
633
634 return Result;
635 }
636
638 {
639 if (Memory == nullptr)
640 {
641 return true;
642 }
643
644 // multi-thread protection
645 FScopeLock ScopeLock(&CriticalSection);
646
647 // starting address space idx used by the chunk containing the allocation
648 for (int32 ChunkIndex = 0; ChunkIndex < AllocChunks.Num(); ChunkIndex++)
649 {
650 ChunkAllocatorType* Chunk = AllocChunks[ChunkIndex];
651 if (Chunk && Chunk->DoesChunkContainAllocation(Memory))
652 {
653#if ALLOCATION_HISTOGRAM
654 PeakAllocationsHistogram[Memory->Size]--;
655
656 // untrack per type allocation info
657 AllocationInfo& TypeAllocInfo = PerTypeAllocationInfo.FindOrAdd(Memory->OwnerType);
658
659 TypeAllocInfo.TotalAllocated -= Memory->Size;
660 TypeAllocInfo.Counts.Frees++;
661#if ALLOCATION_HISTOGRAM_DETAILED
662 TypeAllocInfo.AllocationHistogram[Memory->Size].Frees++;
663#endif
664#endif // ALLOCATION_HISTOGRAM
665
666#if STATS
667 if (OwnerTypeToStatIdMap)
668 {
669 DEC_MEMORY_STAT_BY_FName(OwnerTypeToStatIdMap[Memory->OwnerType], Memory->Size);
670 }
671#endif
672 // free space in the chunk
673 Chunk->Free(Memory);
675
676 // never toss the only chunk
677 if (Chunk->IsEmpty())// && AllocChunks.Num() > 1)
678 {
679 // if empty then unmap and decommit physical memory
680 RemoveAllocChunk(Chunk);
681 }
682
683 // return success
684 return true;
685 }
686 }
687
688 // if we got here, we failed to free the pointer
689 UE_LOG(LogCore, Fatal, TEXT("Tried to free invalid pointer"));
690 return false;
691 }
692
693
695 {
696 // multi-thread protection
697 FScopeLock ScopeLock(&CriticalSection);
698
699 Chunks = 0;
700 // pass off to individual alloc chunks
701 for (int32 ChunkIndex = 0; ChunkIndex < AllocChunks.Num(); ChunkIndex++)
702 {
703 ChunkAllocatorType* Chunk = AllocChunks[ChunkIndex];
704 if (Chunk)
705 {
706 uint64 ChunkUsed = 0;
707 uint64 ChunkFree = 0;
708 Chunk->GetAllocationInfo(ChunkUsed, ChunkFree);
709 Used += ChunkUsed;
710 Free += ChunkFree;
711 Chunks++;
712 }
713 }
714 }
715
716 bool DoesAllocatorContainAddress(const void* Address)
717 {
718 // multi-thread protection
719 FScopeLock ScopeLock(&CriticalSection);
720
721 // loop through the chunks, query each one to see if they contain the address
722 for (int32 ChunkIndex = 0; ChunkIndex < AllocChunks.Num(); ChunkIndex++)
723 {
724 ChunkAllocatorType* Chunk = AllocChunks[ChunkIndex];
725 if (Chunk && Chunk->DoesChunkContainAddress(Address))
726 {
727 return true;
728 }
729 }
730 return false;
731 }
732
734 {
735 FPlatformMisc::LowLevelOutputDebugStringf(TEXT(" Allocator has %d chunks\n"), AllocChunks.Num());
736 FPlatformMisc::LowLevelOutputDebugStringf(TEXT(" Allocator average allocation size is %d (%lld over %lld allocs)\n"), (uint32)((float)TotalAllocated / (float)TotalAllocs), TotalAllocated, TotalAllocs);
737 FPlatformMisc::LowLevelOutputDebugStringf(TEXT(" Allocator average waste (on top of allocation) size is %d (%lld over %lld allocs)\n"), (uint32)((float)TotalWaste / (float)TotalAllocs), TotalWaste, TotalAllocs);
738 }
739
741 {
742 // multi-thread protection
743 FScopeLock ScopeLock(&CriticalSection);
744
745#if ALLOCATION_HISTOGRAM
746 FPlatformMisc::LowLevelOutputDebugStringf(TEXT("Total Allocations Histogram:\n"));
747 for (auto It = TotalAllocationsHistogram.CreateIterator(); It; ++It)
748 {
749 FPlatformMisc::LowLevelOutputDebugStringf(TEXT(" %d, %d\n"), It.Key(), It.Value());
750 }
751#endif // ALLOCATION_HISTOGRAM
752
753 int32 NumChunks = 0;
754 // pass off to individual alloc chunks
755 for (int32 ChunkIndex = 0; ChunkIndex < AllocChunks.Num(); ChunkIndex++)
756 {
757 FPlatformMisc::LowLevelOutputDebugStringf(TEXT("\n-----------------\nChunk %d\n"),ChunkIndex);
758 ChunkAllocatorType* Chunk = AllocChunks[ChunkIndex];
759 if (Chunk)
760 {
761 Chunk->ShowFullAllocationList();
762 }
763 }
764 }
765
767 {
768#if ALLOCATION_HISTOGRAM
769 // we use LowLevel here because we are usually dumping this out while
770 for (auto InfoIt = PerTypeAllocationInfo.CreateConstIterator(); InfoIt; ++InfoIt)
771 {
772 const AllocationInfo& Info = InfoIt.Value();
773
774 if (OwnerTypeToStatIdMap)
775 {
776 FPlatformMisc::LowLevelOutputDebugStringf(TEXT(" '%s': Total: %lld Allocs: %d Frees: %d\n"), *OwnerTypeToStatIdMap[InfoIt.Key()].ToString(), Info.TotalAllocated, Info.Counts.Allocations, Info.Counts.Frees);
777 }
778 else
779 {
780 FPlatformMisc::LowLevelOutputDebugStringf(TEXT(" 'OwnerType %d': %lld Allocs: %d Frees: %d\n"), InfoIt.Key(), Info.TotalAllocated, Info.Counts.Allocations, Info.Counts.Frees);
781 }
782#if ALLOCATION_HISTOGRAM_DETAILED
783 for (auto HistoIt = Info.AllocationHistogram.CreateConstIterator(); HistoIt; ++HistoIt)
784 {
785 FPlatformMisc::LowLevelOutputDebugStringf(TEXT(" %d, %lld, %lld\n"), HistoIt.Key(), HistoIt.Value().Allocations, HistoIt.Value().Frees);
786 }
787#endif
788 }
789#endif // ALLOCATION_HISTOGRAM
790 }
791
792private:
793
795 void UpdateMemoryStatMaxSizes()
796 {
797 }
798
804 ChunkAllocatorType* CreateAllocChunk(uint64 Size)
805 {
806 ChunkAllocatorType* NewChunk = new ChunkAllocatorType(Size, MemoryType, &CriticalSection, UserData);
807 NewChunk->Initialize();
808 INC_MEMORY_STAT_BY_FName(StatRegionName, NewChunk->HeapSize);
809
810 // add a new entry to list (reusing any empty slots)
811 int32 EmptyEntryIdx = AllocChunks.Find(NULL);
813 {
814 EmptyEntryIdx = AllocChunks.Add(NewChunk);
815 }
816 else
817 {
818 AllocChunks[EmptyEntryIdx] = NewChunk;
819 }
820
821#if STATS
822 UpdateMemoryStatMaxSizes();
823#endif
824
825 return NewChunk;
826 }
827
828
835 void RemoveAllocChunk(ChunkAllocatorType* Chunk)
836 {
837 checkSlow(Chunk);
838
839 DEC_MEMORY_STAT_BY_FName(StatRegionName, Chunk->HeapSize);
840
841 // remove entry
842 int32 FoundIdx = AllocChunks.Find(Chunk);
843 check(AllocChunks.IsValidIndex(FoundIdx));
844 AllocChunks[FoundIdx] = NULL;
845 Chunk->Destroy();
846 delete Chunk;
847
848#if STATS
849 UpdateMemoryStatMaxSizes();
850#endif
851 }
852
853
856 {
857#if !UE_BUILD_SHIPPING
858 FPlatformMisc::LowLevelOutputDebugStringf(TEXT("FGrowableAllocator: OOM allocating %dbytes %fMB"), Size, static_cast<float>(Size) / 1024.0f / 1024.0f);
859 UE_LOG(LogCore, Fatal, TEXT("FGrowableAllocator: OOM allocating %dbytes %fMB"), Size, static_cast<float>(Size) / 1024.0f / 1024.0f);
860#endif
861 }
862
863 // size must be aligned at least to this
864 const uint32 SubAllocationAlignment;
865
867 uint64 CurSizeAllocated;
868
870 uint64 TotalAllocationSize;
871 uint64 NumAllocations;
872
874 uint32 MemoryType;
875
877 FName StatRegionName;
878
880 const FName* OwnerTypeToStatIdMap;
881
883 TArray<ChunkAllocatorType*> AllocChunks;
884
885 // extra data to pass to new Chunks
886 void* UserData;
887
888 // a critical section used to coordinate all access in this instance of the allocator and it's chunks
889 FCriticalSection CriticalSection;
890
891#if ALLOCATION_HISTOGRAM
892 struct AllocFreeCounts
893 {
894 uint32 Allocations;
895 uint32 Frees;
896 };
897 struct AllocationInfo
898 {
899 uint64 TotalAllocated;
900#if ALLOCATION_HISTOGRAM_DETAILED
902#endif
903 AllocFreeCounts Counts;
904 };
905
906 TMap<int32, AllocationInfo> PerTypeAllocationInfo;
907
908 TMap<uint64, uint32> TotalAllocationsHistogram;
909 TMap<uint64, uint32> OutstandingAllocationsHistogram;
910 TMap<uint64, uint32> PeakAllocationsHistogram;
911#endif // ALLOCATION_HISTOGRAM
912};
913
#define NULL
Definition oodle2base.h:134
constexpr T Align(T Val, uint64 Alignment)
Definition AlignmentTemplates.h:18
#define checkSlow(expr)
Definition AssertionMacros.h:332
#define check(expr)
Definition AssertionMacros.h:314
#define checkf(expr, format,...)
Definition AssertionMacros.h:315
@ INDEX_NONE
Definition CoreMiscDefines.h:150
#define TEXT(x)
Definition Platform.h:1272
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
FPlatformTypes::uint64 uint64
A 64-bit unsigned integer.
Definition Platform.h:1117
#define DEC_MEMORY_STAT_BY_FName(Stat, Amount)
Definition Stats.h:720
#define INC_MEMORY_STAT_BY_FName(Stat, Amount)
Definition Stats.h:716
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
UE::FPlatformRecursiveMutex FCriticalSection
Definition CriticalSection.h:53
#define UE_LOG(CategoryName, Verbosity, Format,...)
Definition LogMacros.h:270
#define LLM_IF_ENABLED(...)
Definition LowLevelMemTracker.h:1093
void MemoryTrace_Free(uint64 Address, HeapId RootHeap=EMemoryTraceRootHeap::SystemMemory, uint32 ExternalCallstackId=0)
Definition MemoryTrace.h:200
@ SystemMemory
Definition MemoryTrace.h:35
void MemoryTrace_Alloc(uint64 Address, uint64 Size, uint32 Alignment, HeapId RootHeap=EMemoryTraceRootHeap::SystemMemory, uint32 ExternalCallstackId=0)
Definition MemoryTrace.h:199
#define Split(a, ahi, alo)
Definition Predicates.inl:204
uint32 Offset
Definition VulkanMemory.cpp:4033
uint32 Size
Definition VulkanMemory.cpp:4034
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition GenericGrowableAllocator.h:39
virtual uint64 GetWasteApproximation()
Definition GenericGrowableAllocator.h:54
uint64 CurrentAllocs
Definition GenericGrowableAllocator.h:69
virtual ~FGrowableMallocBase()
Definition GenericGrowableAllocator.h:48
uint64 TotalWaste
Definition GenericGrowableAllocator.h:66
FGrowableMallocBase()
Definition GenericGrowableAllocator.h:42
uint64 TotalAllocated
Definition GenericGrowableAllocator.h:63
uint64 TotalAllocs
Definition GenericGrowableAllocator.h:72
Definition GenericGrowableAllocator.h:78
FFreeEntry * FreeList
Definition GenericGrowableAllocator.h:499
FGrowableMallocChunk(uint64 InSize, uint32 Type, FCriticalSection *InCriticalSection)
Definition GenericGrowableAllocator.h:133
void Initialize()
Definition GenericGrowableAllocator.h:142
bool IsEmpty()
Definition GenericGrowableAllocator.h:209
virtual void DestroyInternalMemory()=0
virtual bool DoesChunkContainAllocation(const FGrowableAllocationBase *Allocation)=0
uint64 HeapSize
Definition GenericGrowableAllocator.h:490
uint32 MemoryType
Definition GenericGrowableAllocator.h:487
void Destroy()
Definition GenericGrowableAllocator.h:158
FGrowableAllocationBase * Malloc(uint32 Size, uint32 Alignment, uint32 MinAllocationSize, int32 OwnerType)
Definition GenericGrowableAllocator.h:214
uint64 UsedMemorySize
Definition GenericGrowableAllocator.h:493
bool Free(FGrowableAllocationBase *Memory)
Definition GenericGrowableAllocator.h:283
static const uint32 MaxFreeEntrySizeDirty
Definition GenericGrowableAllocator.h:504
virtual void * GetAddressForTracking(uint32 Offset)=0
void ShowFullAllocationList()
Definition GenericGrowableAllocator.h:365
uint32 MaxFreeEntrySize
Definition GenericGrowableAllocator.h:496
virtual void DestroyAllocationStruct(FGrowableAllocationBase *Allocation)
Definition GenericGrowableAllocator.h:108
virtual ~FGrowableMallocChunk()
Definition GenericGrowableAllocator.h:154
bool CanFitEntry(uint32 Size, uint32 Alignment)
Definition GenericGrowableAllocator.h:170
void GetAllocationInfo(uint64 &Used, uint64 &Free)
Definition GenericGrowableAllocator.h:358
virtual FGrowableAllocationBase * CreateAllocationStruct()=0
FCriticalSection * CriticalSection
Definition GenericGrowableAllocator.h:502
virtual uint64 CreateInternalMemory(uint64 Size)=0
virtual void InitializeAllocationStruct(FGrowableAllocationBase *Allocation)=0
virtual bool DoesChunkContainAddress(const void *Address)=0
Definition NameTypes.h:617
CORE_API FString ToString() const
Definition UnrealNames.cpp:3537
Definition ScopeLock.h:141
Definition Array.h:670
UE_REWRITE SizeType Num() const
Definition Array.h:1144
UE_NODEBUG UE_FORCEINLINE_HINT SizeType Add(ElementType &&Item)
Definition Array.h:2696
UE_NODEBUG UE_FORCEINLINE_HINT bool IsValidIndex(SizeType Index) const
Definition Array.h:1122
UE_NODEBUG UE_FORCEINLINE_HINT bool Find(const ElementType &Item, SizeType &Index) const
Definition Array.h:1302
Definition GenericGrowableAllocator.h:513
TGenericGrowableAllocator(uint64 InitialSize, uint32 InType, uint32 InSubAllocationAlignment, FName InStatRegionName, const FName *InOwnerTypeToStatIdMap, void *InUserData)
Definition GenericGrowableAllocator.h:523
virtual ~TGenericGrowableAllocator()
Definition GenericGrowableAllocator.h:541
void DumpMemoryInfo()
Definition GenericGrowableAllocator.h:766
void ShowAllocationInfo()
Definition GenericGrowableAllocator.h:733
void ShowFullAllocationInfo()
Definition GenericGrowableAllocator.h:740
bool DoesAllocatorContainAddress(const void *Address)
Definition GenericGrowableAllocator.h:716
GrowableAllocationBaseType * Malloc(uint32 Size, uint32 Alignment, int32 OwnerType)
Definition GenericGrowableAllocator.h:563
bool Free(GrowableAllocationBaseType *Memory)
Definition GenericGrowableAllocator.h:637
void GetAllocationInfo(uint32 &Chunks, uint64 &Used, uint64 &Free)
Definition GenericGrowableAllocator.h:694
Definition UnrealString.h.inl:34
U16 Index
Definition radfft.cpp:71
static CORE_API void VARARGS LowLevelOutputDebugStringf(const TCHAR *Format,...)
Definition GenericPlatformMisc.cpp:940
Definition GenericGrowableAllocator.h:28
uint32 Padding
Definition GenericGrowableAllocator.h:31
uint32 Offset
Definition GenericGrowableAllocator.h:30
uint64 Size
Definition GenericGrowableAllocator.h:29
uint32 OwnerType
Definition GenericGrowableAllocator.h:33