Ark Server API (ASA) - Wiki
Loading...
Searching...
No Matches
VirtualAllocator.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"
6#include "HAL/CriticalSection.h"
7#include "HAL/ThreadSafeCounter.h"
8#include "HAL/PlatformProcess.h"
9#include "Misc/ScopeLock.h"
10#include "Templates/AlignmentTemplates.h"
11
13{
14 struct FFreeLink
15 {
16 void *Ptr = nullptr;
17 FFreeLink* Next = nullptr;
18 };
19
21 {
22 int64 AllocBlocksSize = 0;
23 int64 FreeBlocksSize = 0;
24 FFreeLink* FirstFree = nullptr;
25 };
26
28
29 uint8* LowAddress;
31
32 size_t TotalSize;
33 size_t PageSize;
35
36 uint8* NextAlloc;
37
39 int64 LinkSize;
40
42
44
45 void FreeVirtualByBlock(void* Ptr, FPerBlockSize& Block, size_t AlignedSize)
46 {
47 // already locked
48 if (!RecycledLinks)
49 {
50 void *Alloc;
51 // If we ARE malloc, then we know we can (and must) commit part of our range for free links. Otherwise, we can just use malloc (and can't use our VM space anyway)
52 if (bBacksMalloc)
53 {
56 check(Pages && MaximumAlignment % FPlatformMemory::FPlatformVirtualMemoryBlock::GetVirtualSizeAlignment() == 0);
58 VMBlock.Commit();
59 }
60 else
61 {
63 }
64 for (int32 Index = 0; (Index + 1) * sizeof(FFreeLink) <= MaximumAlignment; Index++)
65 {
66 FFreeLink* NewLink = new ((void*)(((uint8*)Alloc + Index * sizeof(FFreeLink)))) FFreeLink;
67 NewLink->Next = RecycledLinks;
68 RecycledLinks = NewLink;
69 }
71 }
72
75 check(!Link->Ptr && Ptr);
76 Link->Ptr = Ptr;
77 Link->Next = Block.FirstFree;
78 Block.FirstFree = Link;
79
80 Block.FreeBlocksSize += AlignedSize;
81 }
82protected:
84 virtual uint8* AllocNewVM(size_t AlignedSize)
85 {
86 uint8* Result = NextAlloc;
87 check(IsAligned(Result, MaximumAlignment) && IsAligned(AlignedSize, MaximumAlignment));
88 NextAlloc = Result + AlignedSize;
90 return Result;
91 }
92
93public:
94
95 FVirtualAllocator(void *InLowAdress, void* InHighAddress, size_t InPageSize, size_t InMaximumAlignment, bool bInBacksMalloc)
96 : LowAddress((uint8*)InLowAdress)
97 , HighAddress((uint8*)InHighAddress)
98 , PageSize(InPageSize)
100 , NextAlloc((uint8*)InLowAdress)
101 , RecycledLinks(nullptr)
102 , LinkSize(0)
103 , bBacksMalloc(bInBacksMalloc)
104 , SpaceConsumed(0)
105 {
107 check(LowAddress && HighAddress && LowAddress < HighAddress && IsAligned(LowAddress, MaximumAlignment));
108 }
109
110 virtual ~FVirtualAllocator() = default;
111
112 uint32 GetPagesForSizeAndAlignment(size_t Size, size_t Alignment = 1) const
113 {
114 check(Alignment <= MaximumAlignment && Alignment > 0);
115 size_t SizeAndAlignment = FMath::Max(Align(Size, Alignment), PageSize);
116 if (SizeAndAlignment * 2 >= TotalSize)
117 {
118 // this is hack, MB3 will ask for tons of virtual and never free it, so we won't round up to power of two
119 size_t Pages = SizeAndAlignment / PageSize;
120 check(Pages == uint32(Pages)); // overflow of uint32
121 return uint32(Pages);
122 }
123 size_t BlockIndex = FMath::CeilLogTwo64(FMath::Max(SizeAndAlignment, PageSize));
124 size_t AlignedSize = size_t(1) << BlockIndex;
125 check(AlignedSize % PageSize == 0);
126 size_t Pages = AlignedSize / PageSize;
127 check(Pages == uint32(Pages)); // overflow of uint32
128 return uint32(Pages);
129 }
130
131 void* AllocateVirtualPages(uint32 NumPages, size_t AlignmentForCheck = 1)
132 {
133 check(AlignmentForCheck <= MaximumAlignment && AlignmentForCheck > 0 && NumPages);
134
135
136 size_t BlockIndex = FMath::CeilLogTwo64(NumPages * PageSize);
137 size_t AlignedSize = size_t(1) << BlockIndex;
138 bool bHackForHugeBlock = false;
139 if (size_t(NumPages) * PageSize * 2 >= TotalSize)
140 {
141 // this is hack, MB3 will ask for tons of virtual and never free it, so we won't round up to power of two
142 AlignedSize = size_t(NumPages) * PageSize;
143 bHackForHugeBlock = true;
144 }
145 FPerBlockSize& Block = Blocks[BlockIndex];
146
148
149
150 uint8* Result;
151 if (Block.FirstFree)
152 {
153 check(!bHackForHugeBlock);
154 Result = (uint8*)Block.FirstFree->Ptr;
155 check(Result);
156 Block.FirstFree->Ptr = nullptr;
157
158 FFreeLink* Next = RecycledLinks;
160 Block.FirstFree = Block.FirstFree->Next;
161 check(!Block.FirstFree || Block.FirstFree->Ptr);
162 RecycledLinks->Next = Next;
163
164 check(IsAligned(Result, FMath::Min(AlignedSize, MaximumAlignment)));
165 Block.FreeBlocksSize -= AlignedSize;
166 }
167 else
168 {
169 size_t AllocSize = FMath::Max(AlignedSize, MaximumAlignment);
170 uint8* LocalNextAlloc = AllocNewVM(AllocSize);
171 check(IsAligned(LocalNextAlloc, MaximumAlignment));
172
173 uint8* NewNextAlloc = LocalNextAlloc + AllocSize;
174
175 if (NewNextAlloc > HighAddress)
176 {
178 }
179
180 Block.AllocBlocksSize += AllocSize;
181 Result = LocalNextAlloc;
182 check(Result);
183 LocalNextAlloc += AlignedSize;
184 while (LocalNextAlloc < NewNextAlloc && !bHackForHugeBlock)
185 {
186 FreeVirtualByBlock(LocalNextAlloc, Block, AlignedSize);
187 LocalNextAlloc += AlignedSize;
188 }
189 }
190 check(IsAligned(Result, AlignmentForCheck));
191 return Result;
192 }
193
194 void FreeVirtual(void* Ptr, uint32 NumPages)
195 {
196 if (size_t(NumPages) * PageSize * 2 >= TotalSize)
197 {
198 // this is hack, MB3 will ask for tons of virtual and never free it, so we won't round up to power of two
199 check(!"Huge vm blocks may not be freed.");
200 return;
201 }
202 size_t BlockIndex = FMath::CeilLogTwo64(NumPages * PageSize);
203 size_t AlignedSize = size_t(1) << BlockIndex;
204
205 FPerBlockSize& Block = Blocks[BlockIndex];
207 FreeVirtualByBlock(Ptr, Block, AlignedSize);
208 }
209
211 {
214 };
216 {
217 size_t PageSize;
222
224
226 };
227
229 {
231 OutStats.PageSize = PageSize;
235 OutStats.FreeListLinks = LinkSize;
236
237 for (int32 Index = 0; Index < 64; Index++)
238 {
241 }
242 }
243};
#define check(expr)
FWindowsCriticalSection FCriticalSection
FWindowsPlatformMemory FPlatformMemory
UE_NODISCARD_CTOR FScopeLock(FCriticalSection *InSynchObject)
Definition ScopeLock.h:35
virtual ~FVirtualAllocator()=default
void * AllocateVirtualPages(uint32 NumPages, size_t AlignmentForCheck=1)
FPerBlockSize Blocks[64]
uint32 GetPagesForSizeAndAlignment(size_t Size, size_t Alignment=1) const
void GetStats(FVirtualAllocatorStats &OutStats)
void FreeVirtual(void *Ptr, uint32 NumPages)
virtual uint8 * AllocNewVM(size_t AlignedSize)
FVirtualAllocator(void *InLowAdress, void *InHighAddress, size_t InPageSize, size_t InMaximumAlignment, bool bInBacksMalloc)
void FreeVirtualByBlock(void *Ptr, FPerBlockSize &Block, size_t AlignedSize)
FFreeLink * RecycledLinks
FCriticalSection CriticalSection
FPlatformVirtualMemoryBlock(void *InPtr, uint32 InVMSizeDivVirtualSizeAlignment)
static void OnOutOfMemory(uint64 Size, uint32 Alignment)
static void * Malloc(SIZE_T Count, uint32 Alignment=DEFAULT_ALIGNMENT)
FVirtualAllocatorStatsPerBlockSize BlockStats[64]