1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
4 #include "MemoryManager.h"
5 #include <CryCore/Platform/platform.h>
7 #include "CustomMemoryHeap.h"
8 #include "GeneralMemoryHeap.h"
9 #include "PageMappingHeap.h"
10 #include "DefragAllocator.h"
12 #if CRY_PLATFORM_WINDOWS
16 #if CRY_PLATFORM_APPLE
17 #include <mach/mach.h> // task_info
20 #if CRY_PLATFORM_LINUX || CRY_PLATFORM_ANDROID || CRY_PLATFORM_APPLE
21 #include <sys/types.h> // required by mman.h
22 #include <sys/mman.h> //mmap - virtual memory manager
24 extern LONG g_TotalAllocatedMemory
;
27 CCryMemoryManager g_memoryManager
;
30 //////////////////////////////////////////////////////////////////////////
31 CCryMemoryManager
* CCryMemoryManager::GetInstance()
34 return &g_memoryManager
;
36 static CCryMemoryManager memman
;
42 #include <CrySystem/IConsole.h>
44 int CCryMemoryManager::s_sys_MemoryDeadListSize
;
46 void CCryMemoryManager::RegisterCVars()
48 REGISTER_CVAR2("sys_MemoryDeadListSize", &s_sys_MemoryDeadListSize
, 0, VF_REQUIRE_APP_RESTART
, "Keep upto size bytes in a \"deadlist\" of allocations to assist in capturing tramples");
52 //////////////////////////////////////////////////////////////////////////
53 bool CCryMemoryManager::GetProcessMemInfo(SProcessMemInfo
& minfo
)
56 #if CRY_PLATFORM_WINDOWS
59 mem
.dwLength
= sizeof(mem
);
60 GlobalMemoryStatusEx(&mem
);
62 minfo
.TotalPhysicalMemory
= mem
.ullTotalPhys
;
63 minfo
.FreePhysicalMemory
= mem
.ullAvailPhys
;
65 //////////////////////////////////////////////////////////////////////////
66 typedef BOOL (WINAPI
* GetProcessMemoryInfoProc
)(HANDLE
, PPROCESS_MEMORY_COUNTERS
, DWORD
);
68 PROCESS_MEMORY_COUNTERS pc
;
71 static HMODULE hPSAPI
= LoadLibraryA("psapi.dll");
74 static GetProcessMemoryInfoProc pGetProcessMemoryInfo
= (GetProcessMemoryInfoProc
)GetProcAddress(hPSAPI
, "GetProcessMemoryInfo");
75 if (pGetProcessMemoryInfo
)
77 if (pGetProcessMemoryInfo(GetCurrentProcess(), &pc
, sizeof(pc
)))
79 minfo
.PageFaultCount
= pc
.PageFaultCount
;
80 minfo
.PeakWorkingSetSize
= pc
.PeakWorkingSetSize
;
81 minfo
.WorkingSetSize
= pc
.WorkingSetSize
;
82 minfo
.QuotaPeakPagedPoolUsage
= pc
.QuotaPeakPagedPoolUsage
;
83 minfo
.QuotaPagedPoolUsage
= pc
.QuotaPagedPoolUsage
;
84 minfo
.QuotaPeakNonPagedPoolUsage
= pc
.QuotaPeakNonPagedPoolUsage
;
85 minfo
.QuotaNonPagedPoolUsage
= pc
.QuotaNonPagedPoolUsage
;
86 minfo
.PagefileUsage
= pc
.PagefileUsage
;
87 minfo
.PeakPagefileUsage
= pc
.PeakPagefileUsage
;
95 #elif CRY_PLATFORM_ORBIS
97 size_t mainMemory
, videoMemory
;
98 VirtualAllocator::QueryMemory(mainMemory
, videoMemory
); // GlobalMemoryStatus would be more accurate but also slower
99 minfo
.TotalPhysicalMemory
= sceKernelGetDirectMemorySize();
100 minfo
.PeakPagefileUsage
= minfo
.PagefileUsage
= mainMemory
+ videoMemory
;
101 minfo
.FreePhysicalMemory
= minfo
.TotalPhysicalMemory
- (mainMemory
+ videoMemory
);
102 #elif CRY_PLATFORM_LINUX || CRY_PLATFORM_ANDROID
104 MEMORYSTATUS MemoryStatus
;
105 GlobalMemoryStatus(&MemoryStatus
);
106 minfo
.PagefileUsage
= minfo
.PeakPagefileUsage
= MemoryStatus
.dwTotalPhys
- MemoryStatus
.dwAvailPhys
;
108 minfo
.FreePhysicalMemory
= MemoryStatus
.dwAvailPhys
;
109 minfo
.TotalPhysicalMemory
= MemoryStatus
.dwTotalPhys
;
111 #if CRY_PLATFORM_ANDROID
112 // On Android, mallinfo() is an EXTREMELY time consuming operation. Nearly 80% CPU time will be spent
113 // on this operation once -memreplay is given. Since WorkingSetSize is only used for statistics and
114 // debugging purpose, it's simply ignored.
115 minfo
.WorkingSetSize
= 0;
117 struct mallinfo meminfo
= mallinfo();
118 minfo
.WorkingSetSize
= meminfo
.usmblks
+ meminfo
.uordblks
;
121 #elif CRY_PLATFORM_APPLE
123 MEMORYSTATUS MemoryStatus
;
124 GlobalMemoryStatus(&MemoryStatus
);
125 minfo
.PagefileUsage
= minfo
.PeakPagefileUsage
= MemoryStatus
.dwTotalPhys
- MemoryStatus
.dwAvailPhys
;
127 minfo
.FreePhysicalMemory
= MemoryStatus
.dwAvailPhys
;
128 minfo
.TotalPhysicalMemory
= MemoryStatus
.dwTotalPhys
;
130 // Retrieve WorkingSetSize from task_info
131 task_basic_info kTaskInfo
;
132 mach_msg_type_number_t
uInfoCount(sizeof(kTaskInfo
) / sizeof(natural_t
));
133 if (task_info(mach_task_self(), TASK_BASIC_INFO
, (task_info_t
)&kTaskInfo
, &uInfoCount
) != 0)
135 gEnv
->pLog
->LogError("task_info failed\n");
138 minfo
.WorkingSetSize
= kTaskInfo
.resident_size
;
139 #elif CRY_PLATFORM_DURANGO
142 TITLEMEMORYSTATUS DurangoMemoryStatus
;
143 DurangoMemoryStatus
.dwLength
= sizeof(DurangoMemoryStatus
);
144 if (TitleMemoryStatus(&DurangoMemoryStatus
) != 0)
146 uint64 titleUsed
= (uint64
)(DurangoMemoryStatus
.ullTitleUsed
);
147 uint64 legacyUsed
= (uint64
)(DurangoMemoryStatus
.ullLegacyUsed
);
148 uint64 total
= (uint64
)(DurangoMemoryStatus
.ullTotalMem
);
150 minfo
.PagefileUsage
= legacyUsed
+ titleUsed
;
152 static uint64 peak
= minfo
.PagefileUsage
;
153 if (peak
< minfo
.PagefileUsage
)
154 peak
= minfo
.PagefileUsage
;
155 minfo
.PeakPagefileUsage
= peak
;
157 minfo
.TotalPhysicalMemory
= total
;
158 minfo
.FreePhysicalMemory
= total
- (legacyUsed
+ titleUsed
);
167 //////////////////////////////////////////////////////////////////////////
168 void CCryMemoryManager::FakeAllocation(long size
)
170 CryInterlockedExchangeAdd((LONG
volatile*)&g_TotalAllocatedMemory
, (LONG
)size
);
173 //////////////////////////////////////////////////////////////////////////
174 CCryMemoryManager::HeapHandle
CCryMemoryManager::TraceDefineHeap(const char* heapName
, size_t size
, const void* pBase
)
179 //////////////////////////////////////////////////////////////////////////
180 void CCryMemoryManager::TraceHeapAlloc(HeapHandle heap
, void* mem
, size_t size
, size_t blockSize
, const char* sUsage
, const char* sNameHint
)
185 //////////////////////////////////////////////////////////////////////////
186 void CCryMemoryManager::TraceHeapFree(HeapHandle heap
, void* mem
, size_t blockSize
)
191 //////////////////////////////////////////////////////////////////////////
192 void CCryMemoryManager::TraceHeapSetColor(uint32 color
)
197 //////////////////////////////////////////////////////////////////////////
198 void CCryMemoryManager::TraceHeapSetLabel(const char* sLabel
)
203 //////////////////////////////////////////////////////////////////////////
204 uint32
CCryMemoryManager::TraceHeapGetColor()
209 //////////////////////////////////////////////////////////////////////////
210 IMemReplay
* CCryMemoryManager::GetIMemReplay()
212 #if CAPTURE_REPLAY_LOG
213 return CMemReplay::GetInstance();
220 //////////////////////////////////////////////////////////////////////////
221 ICustomMemoryHeap
* const CCryMemoryManager::CreateCustomMemoryHeapInstance(IMemoryManager::EAllocPolicy
const eAllocPolicy
)
223 return new CCustomMemoryHeap(eAllocPolicy
);
226 IGeneralMemoryHeap
* CCryMemoryManager::CreateGeneralExpandingMemoryHeap(size_t upperLimit
, size_t reserveSize
, const char* sUsage
)
228 return new CGeneralMemoryHeap(static_cast<UINT_PTR
>(0), upperLimit
, reserveSize
, sUsage
);
231 IGeneralMemoryHeap
* CCryMemoryManager::CreateGeneralMemoryHeap(void* base
, size_t sz
, const char* sUsage
)
233 return new CGeneralMemoryHeap(base
, sz
, sUsage
);
236 IMemoryAddressRange
* CCryMemoryManager::ReserveAddressRange(size_t capacity
, const char* sName
)
238 return new CMemoryAddressRange(capacity
, sName
);
241 IPageMappingHeap
* CCryMemoryManager::CreatePageMappingHeap(size_t addressSpace
, const char* sName
)
243 return new CPageMappingHeap(addressSpace
, sName
);
246 IDefragAllocator
* CCryMemoryManager::CreateDefragAllocator()
248 return new CDefragAllocator();
251 void* CCryMemoryManager::AllocPages(size_t size
)
253 if (size
>= 256 * 1024 * 1024)
255 CryLogAlways("Virtual allocation of size %" PRISIZE_T
" requested!", size
);
256 gEnv
->pSystem
->debug_LogCallStack();
260 MEMREPLAY_SCOPE(EMemReplayAllocClass::C_UserPointer
, EMemReplayUserPointerClass::C_CryMalloc
);
262 #if CRY_PLATFORM_ORBIS
264 return CryModuleMemalign(size
, PAGE_SIZE
);
266 #elif CRY_PLATFORM_LINUX || CRY_PLATFORM_ANDROID || CRY_PLATFORM_APPLE
267 ret
= mmap(0, size
, PROT_READ
| PROT_WRITE
, MAP_ANON
| MAP_PRIVATE
, -1, 0);
270 ret
= VirtualAlloc(NULL
, size
, MEM_COMMIT
| MEM_RESERVE
, PAGE_READWRITE
);
276 MEMREPLAY_SCOPE_ALLOC(ret
, size
, 4096);
282 void CCryMemoryManager::FreePages(void* p
, size_t size
)
284 UINT_PTR id
= (UINT_PTR
)p
;
285 MEMREPLAY_SCOPE(EMemReplayAllocClass::C_UserPointer
, EMemReplayUserPointerClass::C_CryMalloc
);
287 #if CRY_PLATFORM_ORBIS
289 CryModuleMemalignFree(p
);
291 #elif CRY_PLATFORM_LINUX || CRY_PLATFORM_ANDROID || CRY_PLATFORM_APPLE
293 int ret
= munmap(p
, size
);
294 CRY_ASSERT_MESSAGE(ret
== 0, "munmap returned error.");
300 VirtualFree(p
, 0, MEM_RELEASE
);
304 MEMREPLAY_SCOPE_FREE(id
);
307 //////////////////////////////////////////////////////////////////////////
310 CRYMEMORYMANAGER_API
void CryGetIMemoryManagerInterface(void** pIMemoryManager
)
312 // Static instance of the memory manager
313 *pIMemoryManager
= CCryMemoryManager::GetInstance();