chore: remove "using namespace " from AZCore Memory (#6373)
* chore: remove "using namespace " from AZCore Memory REF: https://github.com/o3de/o3de/issues/6281 Signed-off-by: Michael Pollind <mpollind@gmail.com> * chore: fix formatting Signed-off-by: Michael Pollind <mpollind@gmail.com> * chore: fix indentation for AllocatorBase.cpp Signed-off-by: Michael Pollind <mpollind@gmail.com> * chore: fix formatting Signed-off-by: Michael Pollind <mpollind@gmail.com> * chore: address minor checkstyle problems Signed-off-by: Michael Pollind <mpollind@gmail.com>
This commit is contained in:
@@ -16,438 +16,421 @@
|
||||
|
||||
#include <AzCore/Debug/StackTracer.h>
|
||||
|
||||
using namespace AZ;
|
||||
using namespace AZ::Debug;
|
||||
namespace AZ::Debug
|
||||
{
|
||||
// Many PC tools break with alloc/free size mismatches when the memory guard is enabled. Disable for now
|
||||
//#define ENABLE_MEMORY_GUARD
|
||||
|
||||
// Many PC tools break with alloc/free size mismatches when the memory guard is enabled. Disable for now
|
||||
//#define ENABLE_MEMORY_GUARD
|
||||
|
||||
//=========================================================================
|
||||
// AllocationRecords
|
||||
// [9/16/2009]
|
||||
//=========================================================================
|
||||
AllocationRecords::AllocationRecords(unsigned char stackRecordLevels, [[maybe_unused]] bool isMemoryGuard, bool isMarkUnallocatedMemory, const char* allocatorName)
|
||||
: m_mode(AllocatorManager::Instance().m_defaultTrackingRecordMode)
|
||||
, m_isAutoIntegrityCheck(false)
|
||||
, m_isMarkUnallocatedMemory(isMarkUnallocatedMemory)
|
||||
, m_saveNames(false)
|
||||
, m_decodeImmediately(false)
|
||||
, m_numStackLevels(stackRecordLevels)
|
||||
//=========================================================================
|
||||
// AllocationRecords
|
||||
// [9/16/2009]
|
||||
//=========================================================================
|
||||
AllocationRecords::AllocationRecords(
|
||||
unsigned char stackRecordLevels, [[maybe_unused]] bool isMemoryGuard, bool isMarkUnallocatedMemory, const char* allocatorName)
|
||||
: m_mode(AllocatorManager::Instance().m_defaultTrackingRecordMode)
|
||||
, m_isAutoIntegrityCheck(false)
|
||||
, m_isMarkUnallocatedMemory(isMarkUnallocatedMemory)
|
||||
, m_saveNames(false)
|
||||
, m_decodeImmediately(false)
|
||||
, m_numStackLevels(stackRecordLevels)
|
||||
#if defined(ENABLE_MEMORY_GUARD)
|
||||
, m_memoryGuardSize(isMemoryGuard ? sizeof(Debug::GuardValue) : 0)
|
||||
, m_memoryGuardSize(isMemoryGuard ? sizeof(Debug::GuardValue) : 0)
|
||||
#else
|
||||
, m_memoryGuardSize(0)
|
||||
, m_memoryGuardSize(0)
|
||||
#endif
|
||||
, m_requestedAllocs(0)
|
||||
, m_requestedBytes(0)
|
||||
, m_requestedBytesPeak(0)
|
||||
, m_allocatorName(allocatorName)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ~AllocationRecords
|
||||
// [9/16/2009]
|
||||
//=========================================================================
|
||||
AllocationRecords::~AllocationRecords()
|
||||
{
|
||||
if (!AllocatorManager::Instance().m_isAllocatorLeaking)
|
||||
, m_requestedAllocs(0)
|
||||
, m_requestedBytes(0)
|
||||
, m_requestedBytesPeak(0)
|
||||
, m_allocatorName(allocatorName)
|
||||
{
|
||||
// dump all allocation (we should not have any at this point).
|
||||
bool includeNameAndFilename = (m_saveNames || m_mode == RECORD_FULL);
|
||||
EnumerateAllocations(PrintAllocationsCB(true, includeNameAndFilename));
|
||||
AZ_Error("Memory", m_records.empty(), "We still have %d allocations on record! They must be freed prior to destroy!", m_records.size());
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// lock
|
||||
// [9/16/2009]
|
||||
//=========================================================================
|
||||
void
|
||||
AllocationRecords::lock()
|
||||
{
|
||||
m_recordsMutex.lock();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// try_lock
|
||||
// [9/16/2009]
|
||||
//=========================================================================
|
||||
bool AllocationRecords::try_lock()
|
||||
{
|
||||
return m_recordsMutex.try_lock();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// unlock
|
||||
// [9/16/2009]
|
||||
//=========================================================================
|
||||
void
|
||||
AllocationRecords::unlock()
|
||||
{
|
||||
m_recordsMutex.unlock();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// RegisterAllocation
|
||||
// [9/11/2009]
|
||||
//=========================================================================
|
||||
const AllocationInfo*
|
||||
AllocationRecords::RegisterAllocation(void* address, size_t byteSize, size_t alignment, const char* name, const char* fileName, int lineNum, unsigned int stackSuppressCount)
|
||||
{
|
||||
(void)stackSuppressCount;
|
||||
if (m_mode == RECORD_NO_RECORDS)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
if (address == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// memory guard
|
||||
if (m_memoryGuardSize == sizeof(Debug::GuardValue))
|
||||
//=========================================================================
|
||||
// ~AllocationRecords
|
||||
// [9/16/2009]
|
||||
//=========================================================================
|
||||
AllocationRecords::~AllocationRecords()
|
||||
{
|
||||
if (m_isAutoIntegrityCheck)
|
||||
if (!AllocatorManager::Instance().m_isAllocatorLeaking)
|
||||
{
|
||||
IntegrityCheck();
|
||||
// dump all allocation (we should not have any at this point).
|
||||
bool includeNameAndFilename = (m_saveNames || m_mode == RECORD_FULL);
|
||||
EnumerateAllocations(PrintAllocationsCB(true, includeNameAndFilename));
|
||||
AZ_Error(
|
||||
"Memory", m_records.empty(), "We still have %d allocations on record! They must be freed prior to destroy!",
|
||||
m_records.size());
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// lock
|
||||
// [9/16/2009]
|
||||
//=========================================================================
|
||||
void AllocationRecords::lock()
|
||||
{
|
||||
m_recordsMutex.lock();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// try_lock
|
||||
// [9/16/2009]
|
||||
//=========================================================================
|
||||
bool AllocationRecords::try_lock()
|
||||
{
|
||||
return m_recordsMutex.try_lock();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// unlock
|
||||
// [9/16/2009]
|
||||
//=========================================================================
|
||||
void AllocationRecords::unlock()
|
||||
{
|
||||
m_recordsMutex.unlock();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// RegisterAllocation
|
||||
// [9/11/2009]
|
||||
//=========================================================================
|
||||
const AllocationInfo* AllocationRecords::RegisterAllocation(
|
||||
void* address,
|
||||
size_t byteSize,
|
||||
size_t alignment,
|
||||
const char* name,
|
||||
const char* fileName,
|
||||
int lineNum,
|
||||
unsigned int stackSuppressCount)
|
||||
{
|
||||
(void)stackSuppressCount;
|
||||
if (m_mode == RECORD_NO_RECORDS)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
if (address == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AZ_Assert(byteSize>sizeof(Debug::GuardValue), "Did you forget to add the extra MemoryGuardSize() bytes?");
|
||||
byteSize -= sizeof(Debug::GuardValue);
|
||||
new(reinterpret_cast<char*>(address)+byteSize) Debug::GuardValue();
|
||||
}
|
||||
|
||||
Debug::AllocationRecordsType::pair_iter_bool iterBool;
|
||||
{
|
||||
AZStd::scoped_lock lock(m_recordsMutex);
|
||||
iterBool = m_records.insert_key(address);
|
||||
}
|
||||
|
||||
if (!iterBool.second)
|
||||
{
|
||||
// If that memory address was already registered, print the stack trace of the previous registration
|
||||
PrintAllocationsCB(true, (m_saveNames || m_mode == RECORD_FULL))(address, iterBool.first->second, m_numStackLevels);
|
||||
AZ_Assert(iterBool.second, "Memory address 0x%p is already allocated and in the records!", address);
|
||||
}
|
||||
|
||||
Debug::AllocationInfo& ai = iterBool.first->second;
|
||||
ai.m_byteSize = byteSize;
|
||||
ai.m_alignment = static_cast<unsigned int>(alignment);
|
||||
if ((m_saveNames || m_mode == RECORD_FULL) && name && fileName)
|
||||
{
|
||||
// In RECORD_FULL mode or when specifically enabled in app descriptor with
|
||||
// m_allocationRecordsSaveNames, we allocate our own memory to save off name and fileName.
|
||||
// When testing for memory leaks, on process shutdown AllocationRecords::~AllocationRecords
|
||||
// gets called to enumerate the remaining (leaked) allocations. Unfortunately, any names
|
||||
// referenced in dynamic module memory whose modules are unloaded won't be valid
|
||||
// references anymore and we won't get useful information from the enumeration print.
|
||||
// This code block ensures we keep our name/fileName valid for when we need it.
|
||||
const size_t nameLength = strlen(name);
|
||||
const size_t fileNameLength = strlen(fileName);
|
||||
const size_t totalLength = nameLength + fileNameLength + 2; // + 2 for terminating null characters
|
||||
ai.m_namesBlock = m_records.get_allocator().allocate(totalLength, 1);
|
||||
ai.m_namesBlockSize = totalLength;
|
||||
char* savedName = reinterpret_cast<char*>(ai.m_namesBlock);
|
||||
char* savedFileName = savedName + nameLength + 1;
|
||||
memcpy(reinterpret_cast<void*>(savedName), reinterpret_cast<const void*>(name), nameLength + 1);
|
||||
memcpy(reinterpret_cast<void*>(savedFileName), reinterpret_cast<const void*>(fileName), fileNameLength + 1);
|
||||
ai.m_name = savedName;
|
||||
ai.m_fileName = savedFileName;
|
||||
}
|
||||
else
|
||||
{
|
||||
ai.m_name = name;
|
||||
ai.m_fileName = fileName;
|
||||
ai.m_namesBlock = nullptr;
|
||||
ai.m_namesBlockSize = 0;
|
||||
}
|
||||
ai.m_lineNum = lineNum;
|
||||
ai.m_timeStamp = AZStd::GetTimeNowMicroSecond();
|
||||
|
||||
// if we don't have a fileName,lineNum record the stack or if the user requested it.
|
||||
if ((fileName == nullptr && m_mode == RECORD_STACK_IF_NO_FILE_LINE) || m_mode == RECORD_FULL)
|
||||
{
|
||||
ai.m_stackFrames = m_numStackLevels ? reinterpret_cast<AZ::Debug::StackFrame*>(m_records.get_allocator().allocate(sizeof(AZ::Debug::StackFrame)*m_numStackLevels, 1)) : nullptr;
|
||||
if (ai.m_stackFrames)
|
||||
// memory guard
|
||||
if (m_memoryGuardSize == sizeof(Debug::GuardValue))
|
||||
{
|
||||
Debug::StackRecorder::Record(ai.m_stackFrames, m_numStackLevels, stackSuppressCount + 1);
|
||||
|
||||
if (m_decodeImmediately)
|
||||
if (m_isAutoIntegrityCheck)
|
||||
{
|
||||
// OPTIONAL DEBUGGING CODE - enable in app descriptor m_allocationRecordsAttemptDecodeImmediately
|
||||
// This is optionally-enabled code for tracking down memory allocations
|
||||
// that fail to be decoded. DecodeFrames() typically runs at the end of
|
||||
// your application when leaks were found. Sometimes you have stack prints
|
||||
// full of "(module-name not available)" and "(function-name not available)"
|
||||
// that are not actionable. If you have those, enable this code. It'll slow
|
||||
// down your process significantly because for every allocation recorded
|
||||
// we get the stack trace on the spot. Put a breakpoint in DecodeFrames()
|
||||
// at the "(module-name not available)" and "(function-name not available)"
|
||||
// locations and now at the moment those allocations happen you'll have the
|
||||
// full stack trace available and the ability to debug what could be causing it
|
||||
IntegrityCheck();
|
||||
}
|
||||
|
||||
AZ_Assert(byteSize > sizeof(Debug::GuardValue), "Did you forget to add the extra MemoryGuardSize() bytes?");
|
||||
byteSize -= sizeof(Debug::GuardValue);
|
||||
new (reinterpret_cast<char*>(address) + byteSize) Debug::GuardValue();
|
||||
}
|
||||
|
||||
Debug::AllocationRecordsType::pair_iter_bool iterBool;
|
||||
{
|
||||
AZStd::scoped_lock lock(m_recordsMutex);
|
||||
iterBool = m_records.insert_key(address);
|
||||
}
|
||||
|
||||
if (!iterBool.second)
|
||||
{
|
||||
// If that memory address was already registered, print the stack trace of the previous registration
|
||||
PrintAllocationsCB(true, (m_saveNames || m_mode == RECORD_FULL))(address, iterBool.first->second, m_numStackLevels);
|
||||
AZ_Assert(iterBool.second, "Memory address 0x%p is already allocated and in the records!", address);
|
||||
}
|
||||
|
||||
Debug::AllocationInfo& ai = iterBool.first->second;
|
||||
ai.m_byteSize = byteSize;
|
||||
ai.m_alignment = static_cast<unsigned int>(alignment);
|
||||
if ((m_saveNames || m_mode == RECORD_FULL) && name && fileName)
|
||||
{
|
||||
// In RECORD_FULL mode or when specifically enabled in app descriptor with
|
||||
// m_allocationRecordsSaveNames, we allocate our own memory to save off name and fileName.
|
||||
// When testing for memory leaks, on process shutdown AllocationRecords::~AllocationRecords
|
||||
// gets called to enumerate the remaining (leaked) allocations. Unfortunately, any names
|
||||
// referenced in dynamic module memory whose modules are unloaded won't be valid
|
||||
// references anymore and we won't get useful information from the enumeration print.
|
||||
// This code block ensures we keep our name/fileName valid for when we need it.
|
||||
const size_t nameLength = strlen(name);
|
||||
const size_t fileNameLength = strlen(fileName);
|
||||
const size_t totalLength = nameLength + fileNameLength + 2; // + 2 for terminating null characters
|
||||
ai.m_namesBlock = m_records.get_allocator().allocate(totalLength, 1);
|
||||
ai.m_namesBlockSize = totalLength;
|
||||
char* savedName = reinterpret_cast<char*>(ai.m_namesBlock);
|
||||
char* savedFileName = savedName + nameLength + 1;
|
||||
memcpy(reinterpret_cast<void*>(savedName), reinterpret_cast<const void*>(name), nameLength + 1);
|
||||
memcpy(reinterpret_cast<void*>(savedFileName), reinterpret_cast<const void*>(fileName), fileNameLength + 1);
|
||||
ai.m_name = savedName;
|
||||
ai.m_fileName = savedFileName;
|
||||
}
|
||||
else
|
||||
{
|
||||
ai.m_name = name;
|
||||
ai.m_fileName = fileName;
|
||||
ai.m_namesBlock = nullptr;
|
||||
ai.m_namesBlockSize = 0;
|
||||
}
|
||||
ai.m_lineNum = lineNum;
|
||||
ai.m_timeStamp = AZStd::GetTimeNowMicroSecond();
|
||||
|
||||
// if we don't have a fileName,lineNum record the stack or if the user requested it.
|
||||
if ((fileName == nullptr && m_mode == RECORD_STACK_IF_NO_FILE_LINE) || m_mode == RECORD_FULL)
|
||||
{
|
||||
ai.m_stackFrames = m_numStackLevels ? reinterpret_cast<AZ::Debug::StackFrame*>(m_records.get_allocator().allocate(
|
||||
sizeof(AZ::Debug::StackFrame) * m_numStackLevels, 1))
|
||||
: nullptr;
|
||||
if (ai.m_stackFrames)
|
||||
{
|
||||
Debug::StackRecorder::Record(ai.m_stackFrames, m_numStackLevels, stackSuppressCount + 1);
|
||||
|
||||
if (m_decodeImmediately)
|
||||
{
|
||||
const unsigned char decodeStep = 40;
|
||||
Debug::SymbolStorage::StackLine lines[decodeStep];
|
||||
unsigned char iFrame = 0;
|
||||
unsigned char numStackLevels = m_numStackLevels;
|
||||
while (numStackLevels > 0)
|
||||
// OPTIONAL DEBUGGING CODE - enable in app descriptor m_allocationRecordsAttemptDecodeImmediately
|
||||
// This is optionally-enabled code for tracking down memory allocations
|
||||
// that fail to be decoded. DecodeFrames() typically runs at the end of
|
||||
// your application when leaks were found. Sometimes you have stack prints
|
||||
// full of "(module-name not available)" and "(function-name not available)"
|
||||
// that are not actionable. If you have those, enable this code. It'll slow
|
||||
// down your process significantly because for every allocation recorded
|
||||
// we get the stack trace on the spot. Put a breakpoint in DecodeFrames()
|
||||
// at the "(module-name not available)" and "(function-name not available)"
|
||||
// locations and now at the moment those allocations happen you'll have the
|
||||
// full stack trace available and the ability to debug what could be causing it
|
||||
{
|
||||
unsigned char numToDecode = AZStd::GetMin(decodeStep, numStackLevels);
|
||||
Debug::SymbolStorage::DecodeFrames(&ai.m_stackFrames[iFrame], numToDecode, lines);
|
||||
numStackLevels -= numToDecode;
|
||||
iFrame += numToDecode;
|
||||
const unsigned char decodeStep = 40;
|
||||
Debug::SymbolStorage::StackLine lines[decodeStep];
|
||||
unsigned char iFrame = 0;
|
||||
unsigned char numStackLevels = m_numStackLevels;
|
||||
while (numStackLevels > 0)
|
||||
{
|
||||
unsigned char numToDecode = AZStd::GetMin(decodeStep, numStackLevels);
|
||||
Debug::SymbolStorage::DecodeFrames(&ai.m_stackFrames[iFrame], numToDecode, lines);
|
||||
numStackLevels -= numToDecode;
|
||||
iFrame += numToDecode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AllocatorManager::Instance().DebugBreak(address, ai);
|
||||
|
||||
// statistics
|
||||
m_requestedBytes += byteSize;
|
||||
|
||||
size_t currentRequestedBytePeak;
|
||||
size_t newRequestedBytePeak;
|
||||
do
|
||||
{
|
||||
currentRequestedBytePeak = m_requestedBytesPeak.load(std::memory_order::memory_order_relaxed);
|
||||
newRequestedBytePeak = AZStd::GetMax(currentRequestedBytePeak, m_requestedBytes.load(std::memory_order::memory_order_relaxed));
|
||||
} while (!m_requestedBytesPeak.compare_exchange_weak(currentRequestedBytePeak, newRequestedBytePeak));
|
||||
|
||||
++m_requestedAllocs;
|
||||
|
||||
return &ai;
|
||||
}
|
||||
|
||||
AllocatorManager::Instance().DebugBreak(address, ai);
|
||||
|
||||
// statistics
|
||||
m_requestedBytes += byteSize;
|
||||
|
||||
size_t currentRequestedBytePeak;
|
||||
size_t newRequestedBytePeak;
|
||||
do
|
||||
//=========================================================================
|
||||
// UnregisterAllocation
|
||||
// [9/11/2009]
|
||||
//=========================================================================
|
||||
void AllocationRecords::UnregisterAllocation(void* address, size_t byteSize, size_t alignment, AllocationInfo* info)
|
||||
{
|
||||
currentRequestedBytePeak = m_requestedBytesPeak.load(std::memory_order::memory_order_relaxed);
|
||||
newRequestedBytePeak = AZStd::GetMax(currentRequestedBytePeak, m_requestedBytes.load(std::memory_order::memory_order_relaxed));
|
||||
} while (!m_requestedBytesPeak.compare_exchange_weak(currentRequestedBytePeak, newRequestedBytePeak));
|
||||
|
||||
++m_requestedAllocs;
|
||||
|
||||
return &ai;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// UnregisterAllocation
|
||||
// [9/11/2009]
|
||||
//=========================================================================
|
||||
void AllocationRecords::UnregisterAllocation(void* address, size_t byteSize, size_t alignment, AllocationInfo* info)
|
||||
{
|
||||
if (m_mode == RECORD_NO_RECORDS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (address == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AllocationInfo allocationInfo;
|
||||
{
|
||||
AZStd::scoped_lock lock(m_recordsMutex);
|
||||
Debug::AllocationRecordsType::iterator iter = m_records.find(address);
|
||||
// We cannot assert if an allocation does not exist because allocations may have been made before tracking was enabled.
|
||||
// It is currently impossible to actually track all allocations that happen before a certain point
|
||||
// AZ_Assert(iter!=m_records.end(), "Could not find address 0x%p in the allocator!", address);
|
||||
if (iter == m_records.end())
|
||||
if (m_mode == RECORD_NO_RECORDS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
allocationInfo = iter->second;
|
||||
m_records.erase(iter);
|
||||
|
||||
// try to be more aggressive and keep the memory footprint low.
|
||||
// \todo store the load factor at the last rehash to avoid unnecessary rehash
|
||||
if (m_records.load_factor() < 0.9f)
|
||||
if (address == nullptr)
|
||||
{
|
||||
m_records.rehash(0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AllocatorManager::Instance().DebugBreak(address, allocationInfo);
|
||||
|
||||
(void)byteSize;
|
||||
(void)alignment;
|
||||
AZ_Assert(byteSize==0||byteSize==allocationInfo.m_byteSize, "Mismatched byteSize at deallocation! You supplied an invalid value!");
|
||||
AZ_Assert(alignment==0||alignment==allocationInfo.m_alignment, "Mismatched alignment at deallocation! You supplied an invalid value!");
|
||||
|
||||
// statistics
|
||||
m_requestedBytes -= allocationInfo.m_byteSize;
|
||||
|
||||
#if defined(ENABLE_MEMORY_GUARD)
|
||||
// memory guard
|
||||
if (m_memoryGuardSize == sizeof(Debug::GuardValue))
|
||||
{
|
||||
if (m_isAutoIntegrityCheck)
|
||||
{
|
||||
// full integrity check
|
||||
IntegrityCheck();
|
||||
}
|
||||
else
|
||||
{
|
||||
// check current allocation
|
||||
char* guardAddress = reinterpret_cast<char*>(address)+allocationInfo.m_byteSize;
|
||||
Debug::GuardValue* guard = reinterpret_cast<Debug::GuardValue*>(guardAddress);
|
||||
if (!guard->Validate())
|
||||
{
|
||||
AZ_Printf("Memory", "Memory stomp located at address %p, part of allocation:", guardAddress);
|
||||
PrintAllocationsCB printAlloc(true);
|
||||
printAlloc(address, allocationInfo, m_numStackLevels);
|
||||
AZ_Assert(false, "MEMORY STOMP DETECTED!!!");
|
||||
}
|
||||
guard->~GuardValue();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// delete allocation record
|
||||
if (allocationInfo.m_namesBlock)
|
||||
{
|
||||
m_records.get_allocator().deallocate(allocationInfo.m_namesBlock, allocationInfo.m_namesBlockSize, 1);
|
||||
allocationInfo.m_namesBlock = nullptr;
|
||||
allocationInfo.m_namesBlockSize = 0;
|
||||
allocationInfo.m_name = nullptr;
|
||||
allocationInfo.m_fileName = nullptr;
|
||||
}
|
||||
if (allocationInfo.m_stackFrames)
|
||||
{
|
||||
m_records.get_allocator().deallocate(allocationInfo.m_stackFrames, sizeof(AZ::Debug::StackFrame)*m_numStackLevels, 1);
|
||||
allocationInfo.m_stackFrames = nullptr;
|
||||
}
|
||||
|
||||
if (info)
|
||||
{
|
||||
*info = allocationInfo;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// if requested set memory to a specific value.
|
||||
if (m_isMarkUnallocatedMemory)
|
||||
{
|
||||
memset(address, GetUnallocatedMarkValue(), byteSize);
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ResizeAllocation
|
||||
// [9/20/2009]
|
||||
//=========================================================================
|
||||
void
|
||||
AllocationRecords::ResizeAllocation(void* address, size_t newSize)
|
||||
{
|
||||
if (m_mode == RECORD_NO_RECORDS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AllocationInfo* allocationInfo;
|
||||
{
|
||||
AZStd::scoped_lock lock(m_recordsMutex);
|
||||
Debug::AllocationRecordsType::iterator iter = m_records.find(address);
|
||||
AZ_Assert(iter != m_records.end(), "Could not find address 0x%p in the allocator!", address);
|
||||
allocationInfo = &iter->second;
|
||||
}
|
||||
AllocatorManager::Instance().DebugBreak(address, *allocationInfo);
|
||||
|
||||
#if defined(ENABLE_MEMORY_GUARD)
|
||||
if (m_memoryGuardSize == sizeof(Debug::GuardValue))
|
||||
{
|
||||
if (m_isAutoIntegrityCheck)
|
||||
{
|
||||
// full integrity check
|
||||
IntegrityCheck();
|
||||
}
|
||||
else
|
||||
{
|
||||
// check memory guard
|
||||
char* guardAddress = reinterpret_cast<char*>(address) + allocationInfo->m_byteSize;
|
||||
Debug::GuardValue* guard = reinterpret_cast<Debug::GuardValue*>(guardAddress);
|
||||
if (!guard->Validate())
|
||||
{
|
||||
AZ_Printf("Memory", "Memory stomp located at address %p, part of allocation:", guardAddress);
|
||||
PrintAllocationsCB printAlloc(true);
|
||||
printAlloc(address, iter->second, m_numStackLevels);
|
||||
AZ_Assert(false, "MEMORY STOMP DETECTED!!!");
|
||||
}
|
||||
guard->~GuardValue();
|
||||
}
|
||||
// init the new memory guard
|
||||
newSize -= sizeof(Debug::GuardValue);
|
||||
new(reinterpret_cast<char*>(address)+newSize) Debug::GuardValue();
|
||||
}
|
||||
#endif
|
||||
|
||||
// statistics
|
||||
m_requestedBytes -= allocationInfo->m_byteSize;
|
||||
m_requestedBytes += newSize;
|
||||
size_t currentRequestedBytePeak;
|
||||
size_t newRequestedBytePeak;
|
||||
do
|
||||
{
|
||||
currentRequestedBytePeak = m_requestedBytesPeak.load(std::memory_order::memory_order_relaxed);
|
||||
newRequestedBytePeak = AZStd::GetMax(currentRequestedBytePeak, m_requestedBytes.load(std::memory_order::memory_order_relaxed));
|
||||
} while (!m_requestedBytesPeak.compare_exchange_weak(currentRequestedBytePeak, newRequestedBytePeak));
|
||||
++m_requestedAllocs;
|
||||
|
||||
// update allocation size
|
||||
allocationInfo->m_byteSize = newSize;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// EnumerateAllocations
|
||||
// [9/29/2009]
|
||||
//=========================================================================
|
||||
void
|
||||
AllocationRecords::SetMode(Mode mode)
|
||||
{
|
||||
if (mode == RECORD_NO_RECORDS)
|
||||
{
|
||||
AllocationInfo allocationInfo;
|
||||
{
|
||||
AZStd::scoped_lock lock(m_recordsMutex);
|
||||
m_records.clear();
|
||||
Debug::AllocationRecordsType::iterator iter = m_records.find(address);
|
||||
// We cannot assert if an allocation does not exist because allocations may have been made before tracking was enabled.
|
||||
// It is currently impossible to actually track all allocations that happen before a certain point
|
||||
// AZ_Assert(iter!=m_records.end(), "Could not find address 0x%p in the allocator!", address);
|
||||
if (iter == m_records.end())
|
||||
{
|
||||
return;
|
||||
}
|
||||
allocationInfo = iter->second;
|
||||
m_records.erase(iter);
|
||||
|
||||
// try to be more aggressive and keep the memory footprint low.
|
||||
// \todo store the load factor at the last rehash to avoid unnecessary rehash
|
||||
if (m_records.load_factor() < 0.9f)
|
||||
{
|
||||
m_records.rehash(0);
|
||||
}
|
||||
}
|
||||
m_requestedBytes = 0;
|
||||
m_requestedBytesPeak = 0;
|
||||
m_requestedAllocs = 0;
|
||||
}
|
||||
|
||||
AZ_Warning("Memory", m_mode != RECORD_NO_RECORDS || mode == RECORD_NO_RECORDS, "Records recording was disabled and now it's enabled! You might get assert when you free memory, if a you have allocations which were not recorded!");
|
||||
AllocatorManager::Instance().DebugBreak(address, allocationInfo);
|
||||
|
||||
m_mode = mode;
|
||||
}
|
||||
(void)byteSize;
|
||||
(void)alignment;
|
||||
AZ_Assert(
|
||||
byteSize == 0 || byteSize == allocationInfo.m_byteSize, "Mismatched byteSize at deallocation! You supplied an invalid value!");
|
||||
AZ_Assert(
|
||||
alignment == 0 || alignment == allocationInfo.m_alignment,
|
||||
"Mismatched alignment at deallocation! You supplied an invalid value!");
|
||||
|
||||
//=========================================================================
|
||||
// EnumerateAllocations
|
||||
// [9/29/2009]
|
||||
//=========================================================================
|
||||
void
|
||||
AllocationRecords::EnumerateAllocations(AllocationInfoCBType cb)
|
||||
{
|
||||
// enumerate all allocations and stop if requested.
|
||||
// Since allocations can change during the iteration (code that prints out the records could allocate, which will
|
||||
// mutate m_records), we are going to make a copy and iterate the copy.
|
||||
Debug::AllocationRecordsType recordsCopy;
|
||||
{
|
||||
AZStd::scoped_lock lock(m_recordsMutex);
|
||||
recordsCopy = m_records;
|
||||
}
|
||||
for (Debug::AllocationRecordsType::const_iterator iter = recordsCopy.begin(); iter != recordsCopy.end(); ++iter)
|
||||
{
|
||||
if (!cb(iter->first, iter->second, m_numStackLevels))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// statistics
|
||||
m_requestedBytes -= allocationInfo.m_byteSize;
|
||||
|
||||
//=========================================================================
|
||||
// IntegrityCheck
|
||||
// [9/9/2011]
|
||||
//=========================================================================
|
||||
void
|
||||
AllocationRecords::IntegrityCheck() const
|
||||
{
|
||||
#if defined(ENABLE_MEMORY_GUARD)
|
||||
if (m_memoryGuardSize == sizeof(Debug::GuardValue))
|
||||
// memory guard
|
||||
if (m_memoryGuardSize == sizeof(Debug::GuardValue))
|
||||
{
|
||||
if (m_isAutoIntegrityCheck)
|
||||
{
|
||||
// full integrity check
|
||||
IntegrityCheck();
|
||||
}
|
||||
else
|
||||
{
|
||||
// check current allocation
|
||||
char* guardAddress = reinterpret_cast<char*>(address) + allocationInfo.m_byteSize;
|
||||
Debug::GuardValue* guard = reinterpret_cast<Debug::GuardValue*>(guardAddress);
|
||||
if (!guard->Validate())
|
||||
{
|
||||
AZ_Printf("Memory", "Memory stomp located at address %p, part of allocation:", guardAddress);
|
||||
PrintAllocationsCB printAlloc(true);
|
||||
printAlloc(address, allocationInfo, m_numStackLevels);
|
||||
AZ_Assert(false, "MEMORY STOMP DETECTED!!!");
|
||||
}
|
||||
guard->~GuardValue();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// delete allocation record
|
||||
if (allocationInfo.m_namesBlock)
|
||||
{
|
||||
m_records.get_allocator().deallocate(allocationInfo.m_namesBlock, allocationInfo.m_namesBlockSize, 1);
|
||||
allocationInfo.m_namesBlock = nullptr;
|
||||
allocationInfo.m_namesBlockSize = 0;
|
||||
allocationInfo.m_name = nullptr;
|
||||
allocationInfo.m_fileName = nullptr;
|
||||
}
|
||||
if (allocationInfo.m_stackFrames)
|
||||
{
|
||||
m_records.get_allocator().deallocate(allocationInfo.m_stackFrames, sizeof(AZ::Debug::StackFrame) * m_numStackLevels, 1);
|
||||
allocationInfo.m_stackFrames = nullptr;
|
||||
}
|
||||
|
||||
if (info)
|
||||
{
|
||||
*info = allocationInfo;
|
||||
}
|
||||
|
||||
// if requested set memory to a specific value.
|
||||
if (m_isMarkUnallocatedMemory)
|
||||
{
|
||||
memset(address, GetUnallocatedMarkValue(), byteSize);
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ResizeAllocation
|
||||
// [9/20/2009]
|
||||
//=========================================================================
|
||||
void AllocationRecords::ResizeAllocation(void* address, size_t newSize)
|
||||
{
|
||||
if (m_mode == RECORD_NO_RECORDS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AllocationInfo* allocationInfo;
|
||||
{
|
||||
AZStd::scoped_lock lock(m_recordsMutex);
|
||||
Debug::AllocationRecordsType::iterator iter = m_records.find(address);
|
||||
AZ_Assert(iter != m_records.end(), "Could not find address 0x%p in the allocator!", address);
|
||||
allocationInfo = &iter->second;
|
||||
}
|
||||
AllocatorManager::Instance().DebugBreak(address, *allocationInfo);
|
||||
|
||||
#if defined(ENABLE_MEMORY_GUARD)
|
||||
if (m_memoryGuardSize == sizeof(Debug::GuardValue))
|
||||
{
|
||||
if (m_isAutoIntegrityCheck)
|
||||
{
|
||||
// full integrity check
|
||||
IntegrityCheck();
|
||||
}
|
||||
else
|
||||
{
|
||||
// check memory guard
|
||||
char* guardAddress = reinterpret_cast<char*>(address) + allocationInfo->m_byteSize;
|
||||
Debug::GuardValue* guard = reinterpret_cast<Debug::GuardValue*>(guardAddress);
|
||||
if (!guard->Validate())
|
||||
{
|
||||
AZ_Printf("Memory", "Memory stomp located at address %p, part of allocation:", guardAddress);
|
||||
PrintAllocationsCB printAlloc(true);
|
||||
printAlloc(address, iter->second, m_numStackLevels);
|
||||
AZ_Assert(false, "MEMORY STOMP DETECTED!!!");
|
||||
}
|
||||
guard->~GuardValue();
|
||||
}
|
||||
// init the new memory guard
|
||||
newSize -= sizeof(Debug::GuardValue);
|
||||
new (reinterpret_cast<char*>(address) + newSize) Debug::GuardValue();
|
||||
}
|
||||
#endif
|
||||
|
||||
// statistics
|
||||
m_requestedBytes -= allocationInfo->m_byteSize;
|
||||
m_requestedBytes += newSize;
|
||||
size_t currentRequestedBytePeak;
|
||||
size_t newRequestedBytePeak;
|
||||
do
|
||||
{
|
||||
currentRequestedBytePeak = m_requestedBytesPeak.load(std::memory_order::memory_order_relaxed);
|
||||
newRequestedBytePeak = AZStd::GetMax(currentRequestedBytePeak, m_requestedBytes.load(std::memory_order::memory_order_relaxed));
|
||||
} while (!m_requestedBytesPeak.compare_exchange_weak(currentRequestedBytePeak, newRequestedBytePeak));
|
||||
++m_requestedAllocs;
|
||||
|
||||
// update allocation size
|
||||
allocationInfo->m_byteSize = newSize;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// EnumerateAllocations
|
||||
// [9/29/2009]
|
||||
//=========================================================================
|
||||
void AllocationRecords::SetMode(Mode mode)
|
||||
{
|
||||
if (mode == RECORD_NO_RECORDS)
|
||||
{
|
||||
{
|
||||
AZStd::scoped_lock lock(m_recordsMutex);
|
||||
m_records.clear();
|
||||
}
|
||||
m_requestedBytes = 0;
|
||||
m_requestedBytesPeak = 0;
|
||||
m_requestedAllocs = 0;
|
||||
}
|
||||
|
||||
AZ_Warning(
|
||||
"Memory", m_mode != RECORD_NO_RECORDS || mode == RECORD_NO_RECORDS,
|
||||
"Records recording was disabled and now it's enabled! You might get assert when you free memory, if a you have allocations "
|
||||
"which were not recorded!");
|
||||
|
||||
m_mode = mode;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// EnumerateAllocations
|
||||
// [9/29/2009]
|
||||
//=========================================================================
|
||||
void AllocationRecords::EnumerateAllocations(AllocationInfoCBType cb)
|
||||
{
|
||||
// enumerate all allocations and stop if requested.
|
||||
// Since allocations can change during the iteration (code that prints out the records could allocate, which will
|
||||
// mutate m_records), we are going to make a copy and iterate the copy.
|
||||
Debug::AllocationRecordsType recordsCopy;
|
||||
{
|
||||
AZStd::scoped_lock lock(m_recordsMutex);
|
||||
@@ -455,67 +438,93 @@ AllocationRecords::IntegrityCheck() const
|
||||
}
|
||||
for (Debug::AllocationRecordsType::const_iterator iter = recordsCopy.begin(); iter != recordsCopy.end(); ++iter)
|
||||
{
|
||||
// check memory guard
|
||||
const char* guardAddress = reinterpret_cast<const char*>(iter->first)+ iter->second.m_byteSize;
|
||||
if (!reinterpret_cast<const Debug::GuardValue*>(guardAddress)->Validate())
|
||||
if (!cb(iter->first, iter->second, m_numStackLevels))
|
||||
{
|
||||
// We have to turn off the integrity check at this point if we want to succesfully report the memory
|
||||
// stomp we just found. If we don't turn this off, the printf just winds off the stack as each memory
|
||||
// allocation done therein recurses this same code.
|
||||
*const_cast<bool*>(&m_isAutoIntegrityCheck) = false;
|
||||
AZ_Printf("Memory", "Memory stomp located at address %p, part of allocation:", guardAddress);
|
||||
PrintAllocationsCB printAlloc(true);
|
||||
printAlloc(iter->first, iter->second, m_numStackLevels);
|
||||
AZ_Error("Memory", false, "MEMORY STOMP DETECTED!!!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// operator()
|
||||
// [9/29/2009]
|
||||
//=========================================================================
|
||||
bool
|
||||
PrintAllocationsCB::operator()(void* address, const AllocationInfo& info, unsigned char numStackLevels)
|
||||
{
|
||||
if (m_includeNameAndFilename && info.m_name)
|
||||
//=========================================================================
|
||||
// IntegrityCheck
|
||||
// [9/9/2011]
|
||||
//=========================================================================
|
||||
void AllocationRecords::IntegrityCheck() const
|
||||
{
|
||||
AZ_Printf("Memory", "Allocation Name: \"%s\" Addr: 0%p Size: %d Alignment: %d\n", info.m_name, address, info.m_byteSize, info.m_alignment);
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Printf("Memory", "Allocation Addr: 0%p Size: %d Alignment: %d\n", address, info.m_byteSize, info.m_alignment);
|
||||
}
|
||||
|
||||
if (m_isDetailed)
|
||||
{
|
||||
if (!info.m_stackFrames)
|
||||
#if defined(ENABLE_MEMORY_GUARD)
|
||||
if (m_memoryGuardSize == sizeof(Debug::GuardValue))
|
||||
{
|
||||
AZ_Printf("Memory", " %s (%d)\n", info.m_fileName, info.m_lineNum);
|
||||
Debug::AllocationRecordsType recordsCopy;
|
||||
{
|
||||
AZStd::scoped_lock lock(m_recordsMutex);
|
||||
recordsCopy = m_records;
|
||||
}
|
||||
for (Debug::AllocationRecordsType::const_iterator iter = recordsCopy.begin(); iter != recordsCopy.end(); ++iter)
|
||||
{
|
||||
// check memory guard
|
||||
const char* guardAddress = reinterpret_cast<const char*>(iter->first) + iter->second.m_byteSize;
|
||||
if (!reinterpret_cast<const Debug::GuardValue*>(guardAddress)->Validate())
|
||||
{
|
||||
// We have to turn off the integrity check at this point if we want to succesfully report the memory
|
||||
// stomp we just found. If we don't turn this off, the printf just winds off the stack as each memory
|
||||
// allocation done therein recurses this same code.
|
||||
*const_cast<bool*>(&m_isAutoIntegrityCheck) = false;
|
||||
AZ_Printf("Memory", "Memory stomp located at address %p, part of allocation:", guardAddress);
|
||||
PrintAllocationsCB printAlloc(true);
|
||||
printAlloc(iter->first, iter->second, m_numStackLevels);
|
||||
AZ_Error("Memory", false, "MEMORY STOMP DETECTED!!!");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// operator()
|
||||
// [9/29/2009]
|
||||
//=========================================================================
|
||||
bool PrintAllocationsCB::operator()(void* address, const AllocationInfo& info, unsigned char numStackLevels)
|
||||
{
|
||||
if (m_includeNameAndFilename && info.m_name)
|
||||
{
|
||||
AZ_Printf(
|
||||
"Memory", "Allocation Name: \"%s\" Addr: 0%p Size: %d Alignment: %d\n", info.m_name, address, info.m_byteSize,
|
||||
info.m_alignment);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Allocation callstack
|
||||
const unsigned char decodeStep = 40;
|
||||
Debug::SymbolStorage::StackLine lines[decodeStep];
|
||||
unsigned char iFrame = 0;
|
||||
while (numStackLevels>0)
|
||||
AZ_Printf("Memory", "Allocation Addr: 0%p Size: %d Alignment: %d\n", address, info.m_byteSize, info.m_alignment);
|
||||
}
|
||||
|
||||
if (m_isDetailed)
|
||||
{
|
||||
if (!info.m_stackFrames)
|
||||
{
|
||||
unsigned char numToDecode = AZStd::GetMin(decodeStep, numStackLevels);
|
||||
Debug::SymbolStorage::DecodeFrames(&info.m_stackFrames[iFrame], numToDecode, lines);
|
||||
for (unsigned char i = 0; i < numToDecode; ++i)
|
||||
AZ_Printf("Memory", " %s (%d)\n", info.m_fileName, info.m_lineNum);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Allocation callstack
|
||||
const unsigned char decodeStep = 40;
|
||||
Debug::SymbolStorage::StackLine lines[decodeStep];
|
||||
unsigned char iFrame = 0;
|
||||
while (numStackLevels > 0)
|
||||
{
|
||||
if (info.m_stackFrames[iFrame+i].IsValid())
|
||||
unsigned char numToDecode = AZStd::GetMin(decodeStep, numStackLevels);
|
||||
Debug::SymbolStorage::DecodeFrames(&info.m_stackFrames[iFrame], numToDecode, lines);
|
||||
for (unsigned char i = 0; i < numToDecode; ++i)
|
||||
{
|
||||
AZ_Printf("Memory", " %s\n", lines[i]);
|
||||
if (info.m_stackFrames[iFrame + i].IsValid())
|
||||
{
|
||||
AZ_Printf("Memory", " %s\n", lines[i]);
|
||||
}
|
||||
}
|
||||
numStackLevels -= numToDecode;
|
||||
iFrame += numToDecode;
|
||||
}
|
||||
numStackLevels -= numToDecode;
|
||||
iFrame += numToDecode;
|
||||
}
|
||||
}
|
||||
return true; // continue enumerating
|
||||
}
|
||||
return true; // continue enumerating
|
||||
}
|
||||
|
||||
} // namespace AZ::Debug
|
||||
|
||||
@@ -6,194 +6,203 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Memory/Memory.h>
|
||||
#include <AzCore/Memory/AllocatorManager.h>
|
||||
#include <AzCore/Memory/Memory.h>
|
||||
|
||||
using namespace AZ;
|
||||
|
||||
AllocatorBase::AllocatorBase(IAllocatorAllocate* allocationSource, const char* name, const char* desc) :
|
||||
IAllocator(allocationSource),
|
||||
m_name(name),
|
||||
m_desc(desc)
|
||||
namespace AZ
|
||||
{
|
||||
}
|
||||
|
||||
AllocatorBase::~AllocatorBase()
|
||||
{
|
||||
AZ_Assert(!m_isReady, "Allocator %s (%s) is being destructed without first having gone through proper calls to PreDestroy() and Destroy(). Use AllocatorInstance<> for global allocators or AllocatorWrapper<> for local allocators.", m_name, m_desc);
|
||||
}
|
||||
|
||||
const char* AllocatorBase::GetName() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
const char* AllocatorBase::GetDescription() const
|
||||
{
|
||||
return m_desc;
|
||||
}
|
||||
|
||||
IAllocatorAllocate* AllocatorBase::GetSchema()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Debug::AllocationRecords* AllocatorBase::GetRecords()
|
||||
{
|
||||
return m_records;
|
||||
}
|
||||
|
||||
void AllocatorBase::SetRecords(Debug::AllocationRecords* records)
|
||||
{
|
||||
m_records = records;
|
||||
m_memoryGuardSize = records ? records->MemoryGuardSize() : 0;
|
||||
}
|
||||
|
||||
bool AllocatorBase::IsReady() const
|
||||
{
|
||||
return m_isReady;
|
||||
}
|
||||
|
||||
bool AllocatorBase::CanBeOverridden() const
|
||||
{
|
||||
return m_canBeOverridden;
|
||||
}
|
||||
|
||||
void AllocatorBase::PostCreate()
|
||||
{
|
||||
if (m_registrationEnabled)
|
||||
AllocatorBase::AllocatorBase(IAllocatorAllocate* allocationSource, const char* name, const char* desc)
|
||||
: IAllocator(allocationSource)
|
||||
, m_name(name)
|
||||
, m_desc(desc)
|
||||
{
|
||||
if (AZ::Environment::IsReady())
|
||||
}
|
||||
|
||||
AllocatorBase::~AllocatorBase()
|
||||
{
|
||||
AZ_Assert(
|
||||
!m_isReady,
|
||||
"Allocator %s (%s) is being destructed without first having gone through proper calls to PreDestroy() and Destroy(). Use "
|
||||
"AllocatorInstance<> for global allocators or AllocatorWrapper<> for local allocators.",
|
||||
m_name, m_desc);
|
||||
}
|
||||
|
||||
const char* AllocatorBase::GetName() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
const char* AllocatorBase::GetDescription() const
|
||||
{
|
||||
return m_desc;
|
||||
}
|
||||
|
||||
IAllocatorAllocate* AllocatorBase::GetSchema()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Debug::AllocationRecords* AllocatorBase::GetRecords()
|
||||
{
|
||||
return m_records;
|
||||
}
|
||||
|
||||
void AllocatorBase::SetRecords(Debug::AllocationRecords* records)
|
||||
{
|
||||
m_records = records;
|
||||
m_memoryGuardSize = records ? records->MemoryGuardSize() : 0;
|
||||
}
|
||||
|
||||
bool AllocatorBase::IsReady() const
|
||||
{
|
||||
return m_isReady;
|
||||
}
|
||||
|
||||
bool AllocatorBase::CanBeOverridden() const
|
||||
{
|
||||
return m_canBeOverridden;
|
||||
}
|
||||
|
||||
void AllocatorBase::PostCreate()
|
||||
{
|
||||
if (m_registrationEnabled)
|
||||
{
|
||||
AllocatorManager::Instance().RegisterAllocator(this);
|
||||
if (AZ::Environment::IsReady())
|
||||
{
|
||||
AllocatorManager::Instance().RegisterAllocator(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
AllocatorManager::PreRegisterAllocator(this);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
const auto debugConfig = GetDebugConfig();
|
||||
if (!debugConfig.m_excludeFromDebugging)
|
||||
{
|
||||
AllocatorManager::PreRegisterAllocator(this);
|
||||
SetRecords(aznew Debug::AllocationRecords(
|
||||
(unsigned char)debugConfig.m_stackRecordLevels, debugConfig.m_usesMemoryGuards, debugConfig.m_marksUnallocatedMemory,
|
||||
GetName()));
|
||||
}
|
||||
|
||||
m_isReady = true;
|
||||
}
|
||||
|
||||
const auto debugConfig = GetDebugConfig();
|
||||
if (!debugConfig.m_excludeFromDebugging)
|
||||
void AllocatorBase::PreDestroy()
|
||||
{
|
||||
SetRecords(aznew Debug::AllocationRecords((unsigned char)debugConfig.m_stackRecordLevels, debugConfig.m_usesMemoryGuards, debugConfig.m_marksUnallocatedMemory, GetName()));
|
||||
Debug::AllocationRecords* allocatorRecords = GetRecords();
|
||||
if (allocatorRecords)
|
||||
{
|
||||
delete allocatorRecords;
|
||||
SetRecords(nullptr);
|
||||
}
|
||||
|
||||
if (m_registrationEnabled && AZ::AllocatorManager::IsReady())
|
||||
{
|
||||
AllocatorManager::Instance().UnRegisterAllocator(this);
|
||||
}
|
||||
|
||||
m_isReady = false;
|
||||
}
|
||||
|
||||
m_isReady = true;
|
||||
}
|
||||
|
||||
void AllocatorBase::PreDestroy()
|
||||
{
|
||||
Debug::AllocationRecords* allocatorRecords = GetRecords();
|
||||
if(allocatorRecords)
|
||||
void AllocatorBase::SetLazilyCreated(bool lazy)
|
||||
{
|
||||
delete allocatorRecords;
|
||||
SetRecords(nullptr);
|
||||
m_isLazilyCreated = lazy;
|
||||
}
|
||||
|
||||
if (m_registrationEnabled && AZ::AllocatorManager::IsReady())
|
||||
bool AllocatorBase::IsLazilyCreated() const
|
||||
{
|
||||
AllocatorManager::Instance().UnRegisterAllocator(this);
|
||||
return m_isLazilyCreated;
|
||||
}
|
||||
|
||||
m_isReady = false;
|
||||
}
|
||||
void AllocatorBase::SetProfilingActive(bool active)
|
||||
{
|
||||
m_isProfilingActive = active;
|
||||
}
|
||||
|
||||
void AllocatorBase::SetLazilyCreated(bool lazy)
|
||||
{
|
||||
m_isLazilyCreated = lazy;
|
||||
}
|
||||
bool AllocatorBase::IsProfilingActive() const
|
||||
{
|
||||
return m_isProfilingActive;
|
||||
}
|
||||
|
||||
bool AllocatorBase::IsLazilyCreated() const
|
||||
{
|
||||
return m_isLazilyCreated;
|
||||
}
|
||||
void AllocatorBase::DisableOverriding()
|
||||
{
|
||||
m_canBeOverridden = false;
|
||||
}
|
||||
|
||||
void AllocatorBase::SetProfilingActive(bool active)
|
||||
{
|
||||
m_isProfilingActive = active;
|
||||
}
|
||||
void AllocatorBase::DisableRegistration()
|
||||
{
|
||||
m_registrationEnabled = false;
|
||||
}
|
||||
|
||||
bool AllocatorBase::IsProfilingActive() const
|
||||
{
|
||||
return m_isProfilingActive;
|
||||
}
|
||||
|
||||
void AllocatorBase::DisableOverriding()
|
||||
{
|
||||
m_canBeOverridden = false;
|
||||
}
|
||||
|
||||
void AllocatorBase::DisableRegistration()
|
||||
{
|
||||
m_registrationEnabled = false;
|
||||
}
|
||||
|
||||
void AllocatorBase::ProfileAllocation(void* ptr, size_t byteSize, size_t alignment, const char* name, const char* fileName, int lineNum, int suppressStackRecord)
|
||||
{
|
||||
void AllocatorBase::ProfileAllocation(
|
||||
void* ptr, size_t byteSize, size_t alignment, const char* name, const char* fileName, int lineNum, int suppressStackRecord)
|
||||
{
|
||||
#if defined(AZ_HAS_VARIADIC_TEMPLATES) && defined(AZ_DEBUG_BUILD)
|
||||
++suppressStackRecord; // one more for the fact the ebus is a function
|
||||
++suppressStackRecord; // one more for the fact the ebus is a function
|
||||
#endif // AZ_HAS_VARIADIC_TEMPLATES
|
||||
|
||||
if (m_isProfilingActive)
|
||||
{
|
||||
auto records = GetRecords();
|
||||
if (records)
|
||||
if (m_isProfilingActive)
|
||||
{
|
||||
records->RegisterAllocation(ptr, byteSize, alignment, name, fileName, lineNum, suppressStackRecord + 1);
|
||||
auto records = GetRecords();
|
||||
if (records)
|
||||
{
|
||||
records->RegisterAllocation(ptr, byteSize, alignment, name, fileName, lineNum, suppressStackRecord + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AllocatorBase::ProfileDeallocation(void* ptr, size_t byteSize, size_t alignment, Debug::AllocationInfo* info)
|
||||
{
|
||||
if (m_isProfilingActive)
|
||||
void AllocatorBase::ProfileDeallocation(void* ptr, size_t byteSize, size_t alignment, Debug::AllocationInfo* info)
|
||||
{
|
||||
auto records = GetRecords();
|
||||
if (records)
|
||||
if (m_isProfilingActive)
|
||||
{
|
||||
records->UnregisterAllocation(ptr, byteSize, alignment, info);
|
||||
auto records = GetRecords();
|
||||
if (records)
|
||||
{
|
||||
records->UnregisterAllocation(ptr, byteSize, alignment, info);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AllocatorBase::ProfileReallocationBegin([[maybe_unused]] void* ptr, [[maybe_unused]] size_t newSize)
|
||||
{
|
||||
}
|
||||
|
||||
void AllocatorBase::ProfileReallocationEnd(void* ptr, void* newPtr, size_t newSize, size_t newAlignment)
|
||||
{
|
||||
if (m_isProfilingActive)
|
||||
void AllocatorBase::ProfileReallocationBegin([[maybe_unused]] void* ptr, [[maybe_unused]] size_t newSize)
|
||||
{
|
||||
Debug::AllocationInfo info;
|
||||
ProfileDeallocation(ptr, 0, 0, &info);
|
||||
ProfileAllocation(newPtr, newSize, newAlignment, info.m_name, info.m_fileName, info.m_lineNum, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void AllocatorBase::ProfileReallocation(void* ptr, void* newPtr, size_t newSize, size_t newAlignment)
|
||||
{
|
||||
ProfileReallocationEnd(ptr, newPtr, newSize, newAlignment);
|
||||
}
|
||||
|
||||
void AllocatorBase::ProfileResize(void* ptr, size_t newSize)
|
||||
{
|
||||
if (newSize && m_isProfilingActive)
|
||||
void AllocatorBase::ProfileReallocationEnd(void* ptr, void* newPtr, size_t newSize, size_t newAlignment)
|
||||
{
|
||||
auto records = GetRecords();
|
||||
if (records)
|
||||
if (m_isProfilingActive)
|
||||
{
|
||||
records->ResizeAllocation(ptr, newSize);
|
||||
Debug::AllocationInfo info;
|
||||
ProfileDeallocation(ptr, 0, 0, &info);
|
||||
ProfileAllocation(newPtr, newSize, newAlignment, info.m_name, info.m_fileName, info.m_lineNum, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool AllocatorBase::OnOutOfMemory(size_t byteSize, size_t alignment, int flags, const char* name, const char* fileName, int lineNum)
|
||||
{
|
||||
if (AllocatorManager::IsReady() && AllocatorManager::Instance().m_outOfMemoryListener)
|
||||
void AllocatorBase::ProfileReallocation(void* ptr, void* newPtr, size_t newSize, size_t newAlignment)
|
||||
{
|
||||
AllocatorManager::Instance().m_outOfMemoryListener(this, byteSize, alignment, flags, name, fileName, lineNum);
|
||||
return true;
|
||||
ProfileReallocationEnd(ptr, newPtr, newSize, newAlignment);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AllocatorBase::ProfileResize(void* ptr, size_t newSize)
|
||||
{
|
||||
if (newSize && m_isProfilingActive)
|
||||
{
|
||||
auto records = GetRecords();
|
||||
if (records)
|
||||
{
|
||||
records->ResizeAllocation(ptr, newSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool AllocatorBase::OnOutOfMemory(size_t byteSize, size_t alignment, int flags, const char* name, const char* fileName, int lineNum)
|
||||
{
|
||||
if (AllocatorManager::IsReady() && AllocatorManager::Instance().m_outOfMemoryListener)
|
||||
{
|
||||
AllocatorManager::Instance().m_outOfMemoryListener(this, byteSize, alignment, flags, name, fileName, lineNum);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace AZ
|
||||
|
||||
@@ -13,186 +13,182 @@
|
||||
|
||||
#include <AzCore/std/functional.h>
|
||||
|
||||
using namespace AZ;
|
||||
|
||||
//=========================================================================
|
||||
// BestFitExternalMapAllocator
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapAllocator::BestFitExternalMapAllocator()
|
||||
: AllocatorBase(this, "BestFitExternalMapAllocator", "Best fit allocator with external tracking storage!")
|
||||
, m_schema(nullptr)
|
||||
{}
|
||||
|
||||
//=========================================================================
|
||||
// Create
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
bool
|
||||
BestFitExternalMapAllocator::Create(const Descriptor& desc)
|
||||
namespace AZ
|
||||
{
|
||||
AZ_Assert(IsReady() == false, "BestFitExternalMapAllocator was already created!");
|
||||
if (IsReady())
|
||||
//=========================================================================
|
||||
// BestFitExternalMapAllocator
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapAllocator::BestFitExternalMapAllocator()
|
||||
: AllocatorBase(this, "BestFitExternalMapAllocator", "Best fit allocator with external tracking storage!")
|
||||
, m_schema(nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isReady = true;
|
||||
|
||||
m_desc = desc;
|
||||
BestFitExternalMapSchema::Descriptor schemaDesc;
|
||||
schemaDesc.m_mapAllocator = desc.m_mapAllocator;
|
||||
schemaDesc.m_memoryBlock = desc.m_memoryBlock;
|
||||
schemaDesc.m_memoryBlockByteSize = desc.m_memoryBlockByteSize;
|
||||
|
||||
m_schema = azcreate(BestFitExternalMapSchema, (schemaDesc), SystemAllocator);
|
||||
if (m_schema == nullptr)
|
||||
//=========================================================================
|
||||
// Create
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
bool BestFitExternalMapAllocator::Create(const Descriptor& desc)
|
||||
{
|
||||
isReady = false;
|
||||
AZ_Assert(IsReady() == false, "BestFitExternalMapAllocator was already created!");
|
||||
if (IsReady())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isReady = true;
|
||||
|
||||
m_desc = desc;
|
||||
BestFitExternalMapSchema::Descriptor schemaDesc;
|
||||
schemaDesc.m_mapAllocator = desc.m_mapAllocator;
|
||||
schemaDesc.m_memoryBlock = desc.m_memoryBlock;
|
||||
schemaDesc.m_memoryBlockByteSize = desc.m_memoryBlockByteSize;
|
||||
|
||||
m_schema = azcreate(BestFitExternalMapSchema, (schemaDesc), SystemAllocator);
|
||||
if (m_schema == nullptr)
|
||||
{
|
||||
isReady = false;
|
||||
}
|
||||
|
||||
return isReady;
|
||||
}
|
||||
|
||||
return isReady;
|
||||
}
|
||||
//=========================================================================
|
||||
// Destroy
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
void BestFitExternalMapAllocator::Destroy()
|
||||
{
|
||||
azdestroy(m_schema, SystemAllocator);
|
||||
m_schema = nullptr;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Destroy
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
void
|
||||
BestFitExternalMapAllocator::Destroy()
|
||||
{
|
||||
azdestroy(m_schema, SystemAllocator);
|
||||
m_schema = nullptr;
|
||||
}
|
||||
AllocatorDebugConfig BestFitExternalMapAllocator::GetDebugConfig()
|
||||
{
|
||||
return AllocatorDebugConfig()
|
||||
.ExcludeFromDebugging(!m_desc.m_allocationRecords)
|
||||
.StackRecordLevels(m_desc.m_stackRecordLevels)
|
||||
.MarksUnallocatedMemory(false)
|
||||
.UsesMemoryGuards(false);
|
||||
}
|
||||
|
||||
AllocatorDebugConfig BestFitExternalMapAllocator::GetDebugConfig()
|
||||
{
|
||||
return AllocatorDebugConfig()
|
||||
.ExcludeFromDebugging(!m_desc.m_allocationRecords)
|
||||
.StackRecordLevels(m_desc.m_stackRecordLevels)
|
||||
.MarksUnallocatedMemory(false)
|
||||
.UsesMemoryGuards(false);
|
||||
}
|
||||
//=========================================================================
|
||||
// Allocate
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapAllocator::pointer_type BestFitExternalMapAllocator::Allocate(
|
||||
size_type byteSize,
|
||||
size_type alignment,
|
||||
int flags,
|
||||
[[maybe_unused]] const char* name,
|
||||
[[maybe_unused]] const char* fileName,
|
||||
[[maybe_unused]] int lineNum,
|
||||
unsigned int suppressStackRecord)
|
||||
{
|
||||
(void)suppressStackRecord;
|
||||
|
||||
//=========================================================================
|
||||
// Allocate
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapAllocator::pointer_type BestFitExternalMapAllocator::Allocate(
|
||||
size_type byteSize,
|
||||
size_type alignment,
|
||||
int flags,
|
||||
[[maybe_unused]] const char* name,
|
||||
[[maybe_unused]] const char* fileName,
|
||||
[[maybe_unused]] int lineNum,
|
||||
unsigned int suppressStackRecord)
|
||||
{
|
||||
(void)suppressStackRecord;
|
||||
AZ_Assert(byteSize > 0, "You can not allocate 0 bytes!");
|
||||
AZ_Assert((alignment & (alignment - 1)) == 0, "Alignment must be power of 2!");
|
||||
byteSize = MemorySizeAdjustedUp(byteSize);
|
||||
|
||||
AZ_Assert(byteSize > 0, "You can not allocate 0 bytes!");
|
||||
AZ_Assert((alignment & (alignment - 1)) == 0, "Alignment must be power of 2!");
|
||||
byteSize = MemorySizeAdjustedUp(byteSize);
|
||||
BestFitExternalMapAllocator::pointer_type address = m_schema->Allocate(byteSize, alignment, flags);
|
||||
AZ_Assert(
|
||||
address != nullptr, "BestFitExternalMapAllocator: Failed to allocate %d bytes aligned on %d (flags: 0x%08x) %s : %s (%d)!",
|
||||
byteSize, alignment, flags, name ? name : "(no name)", fileName ? fileName : "(no file name)", lineNum);
|
||||
AZ_MEMORY_PROFILE(ProfileAllocation(address, byteSize, alignment, name, fileName, lineNum, suppressStackRecord + 1));
|
||||
|
||||
BestFitExternalMapAllocator::pointer_type address = m_schema->Allocate(byteSize, alignment, flags);
|
||||
AZ_Assert(address != nullptr, "BestFitExternalMapAllocator: Failed to allocate %d bytes aligned on %d (flags: 0x%08x) %s : %s (%d)!", byteSize, alignment, flags, name ? name : "(no name)", fileName ? fileName : "(no file name)", lineNum);
|
||||
AZ_MEMORY_PROFILE(ProfileAllocation(address, byteSize, alignment, name, fileName, lineNum, suppressStackRecord + 1));
|
||||
return address;
|
||||
}
|
||||
|
||||
return address;
|
||||
}
|
||||
//=========================================================================
|
||||
// DeAllocate
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
void BestFitExternalMapAllocator::DeAllocate(pointer_type ptr, size_type byteSize, size_type alignment)
|
||||
{
|
||||
byteSize = MemorySizeAdjustedUp(byteSize);
|
||||
AZ_MEMORY_PROFILE(ProfileDeallocation(ptr, byteSize, alignment, nullptr));
|
||||
|
||||
//=========================================================================
|
||||
// DeAllocate
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
void
|
||||
BestFitExternalMapAllocator::DeAllocate(pointer_type ptr, size_type byteSize, size_type alignment)
|
||||
{
|
||||
byteSize = MemorySizeAdjustedUp(byteSize);
|
||||
AZ_MEMORY_PROFILE(ProfileDeallocation(ptr, byteSize, alignment, nullptr));
|
||||
(void)byteSize;
|
||||
(void)alignment;
|
||||
m_schema->DeAllocate(ptr);
|
||||
}
|
||||
|
||||
(void)byteSize;
|
||||
(void)alignment;
|
||||
m_schema->DeAllocate(ptr);
|
||||
}
|
||||
//=========================================================================
|
||||
// Resize
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapAllocator::size_type BestFitExternalMapAllocator::Resize(pointer_type ptr, size_type newSize)
|
||||
{
|
||||
(void)ptr;
|
||||
(void)newSize;
|
||||
/* todo */
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Resize
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapAllocator::size_type
|
||||
BestFitExternalMapAllocator::Resize(pointer_type ptr, size_type newSize)
|
||||
{
|
||||
(void)ptr;
|
||||
(void)newSize;
|
||||
/* todo */
|
||||
return 0;
|
||||
}
|
||||
//=========================================================================
|
||||
// ReAllocate
|
||||
// [9/13/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapAllocator::pointer_type BestFitExternalMapAllocator::ReAllocate(
|
||||
pointer_type ptr, size_type newSize, size_type newAlignment)
|
||||
{
|
||||
(void)ptr;
|
||||
(void)newSize;
|
||||
(void)newAlignment;
|
||||
AZ_Assert(false, "Not supported!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ReAllocate
|
||||
// [9/13/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapAllocator::pointer_type
|
||||
BestFitExternalMapAllocator::ReAllocate(pointer_type ptr, size_type newSize, size_type newAlignment)
|
||||
{
|
||||
(void)ptr;
|
||||
(void)newSize;
|
||||
(void)newAlignment;
|
||||
AZ_Assert(false, "Not supported!");
|
||||
return nullptr;
|
||||
}
|
||||
//=========================================================================
|
||||
// AllocationSize
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapAllocator::size_type BestFitExternalMapAllocator::AllocationSize(pointer_type ptr)
|
||||
{
|
||||
return MemorySizeAdjustedDown(m_schema->AllocationSize(ptr));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// AllocationSize
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapAllocator::size_type
|
||||
BestFitExternalMapAllocator::AllocationSize(pointer_type ptr)
|
||||
{
|
||||
return MemorySizeAdjustedDown(m_schema->AllocationSize(ptr));
|
||||
}
|
||||
//=========================================================================
|
||||
// NumAllocatedBytes
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapAllocator::size_type BestFitExternalMapAllocator::NumAllocatedBytes() const
|
||||
{
|
||||
return m_schema->NumAllocatedBytes();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// NumAllocatedBytes
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapAllocator::size_type
|
||||
BestFitExternalMapAllocator::NumAllocatedBytes() const
|
||||
{
|
||||
return m_schema->NumAllocatedBytes();
|
||||
}
|
||||
//=========================================================================
|
||||
// Capacity
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapAllocator::size_type BestFitExternalMapAllocator::Capacity() const
|
||||
{
|
||||
return m_schema->Capacity();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Capacity
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapAllocator::size_type
|
||||
BestFitExternalMapAllocator::Capacity() const
|
||||
{
|
||||
return m_schema->Capacity();
|
||||
}
|
||||
//=========================================================================
|
||||
// GetMaxAllocationSize
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapAllocator::size_type BestFitExternalMapAllocator::GetMaxAllocationSize() const
|
||||
{
|
||||
return m_schema->GetMaxAllocationSize();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// GetMaxAllocationSize
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapAllocator::size_type
|
||||
BestFitExternalMapAllocator::GetMaxAllocationSize() const
|
||||
{
|
||||
return m_schema->GetMaxAllocationSize();
|
||||
}
|
||||
auto BestFitExternalMapAllocator::GetMaxContiguousAllocationSize() const -> size_type
|
||||
{
|
||||
return m_schema->GetMaxContiguousAllocationSize();
|
||||
}
|
||||
|
||||
auto BestFitExternalMapAllocator::GetMaxContiguousAllocationSize() const -> size_type
|
||||
{
|
||||
return m_schema->GetMaxContiguousAllocationSize();
|
||||
}
|
||||
//=========================================================================
|
||||
// GetSubAllocator
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
IAllocatorAllocate* BestFitExternalMapAllocator::GetSubAllocator()
|
||||
{
|
||||
return m_schema->GetSubAllocator();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// GetSubAllocator
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
IAllocatorAllocate*
|
||||
BestFitExternalMapAllocator::GetSubAllocator()
|
||||
{
|
||||
return m_schema->GetSubAllocator();
|
||||
}
|
||||
} // namespace AZ
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#ifndef AZ_BEST_FIT_EXT_MAP_ALLOCATOR_H
|
||||
#define AZ_BEST_FIT_EXT_MAP_ALLOCATOR_H
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Memory/Memory.h>
|
||||
|
||||
@@ -76,7 +75,3 @@ namespace AZ
|
||||
};
|
||||
}
|
||||
|
||||
#endif // AZ_BEST_FIT_EXT_MAP_ALLOCATOR_H
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
@@ -9,194 +9,199 @@
|
||||
#include <AzCore/Memory/BestFitExternalMapSchema.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
|
||||
using namespace AZ;
|
||||
|
||||
//=========================================================================
|
||||
// BestFitExternalMapSchema
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapSchema::BestFitExternalMapSchema(const Descriptor& desc)
|
||||
: m_desc(desc)
|
||||
, m_used(0)
|
||||
, m_freeChunksMap(FreeMapType::key_compare(), AZStdIAllocator(desc.m_mapAllocator != nullptr ? desc.m_mapAllocator : &AllocatorInstance<SystemAllocator>::Get()))
|
||||
, m_allocChunksMap(AllocMapType::hasher(), AllocMapType::key_eq(), AZStdIAllocator(desc.m_mapAllocator != nullptr ? desc.m_mapAllocator : &AllocatorInstance<SystemAllocator>::Get()))
|
||||
namespace AZ
|
||||
{
|
||||
if (m_desc.m_mapAllocator == nullptr)
|
||||
//=========================================================================
|
||||
// BestFitExternalMapSchema
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapSchema::BestFitExternalMapSchema(const Descriptor& desc)
|
||||
: m_desc(desc)
|
||||
, m_used(0)
|
||||
, m_freeChunksMap(
|
||||
FreeMapType::key_compare(),
|
||||
AZStdIAllocator(desc.m_mapAllocator != nullptr ? desc.m_mapAllocator : &AllocatorInstance<SystemAllocator>::Get()))
|
||||
, m_allocChunksMap(
|
||||
AllocMapType::hasher(),
|
||||
AllocMapType::key_eq(),
|
||||
AZStdIAllocator(desc.m_mapAllocator != nullptr ? desc.m_mapAllocator : &AllocatorInstance<SystemAllocator>::Get()))
|
||||
{
|
||||
m_desc.m_mapAllocator = &AllocatorInstance<SystemAllocator>::Get(); // used as our sub allocator
|
||||
}
|
||||
AZ_Assert(m_desc.m_memoryBlockByteSize > 0, "You must provide memory block size!");
|
||||
AZ_Assert(m_desc.m_memoryBlock != nullptr, "You must provide memory block allocated as you with!");
|
||||
//if( m_desc.m_memoryBlock == NULL) there is no point to automate this cause we need to flag this memory special, otherwise there is no point to use this allocator at all
|
||||
// m_desc.m_memoryBlock = azmalloc(SystemAllocator,m_desc.m_memoryBlockByteSize,16);
|
||||
m_freeChunksMap.insert(AZStd::make_pair(m_desc.m_memoryBlockByteSize, reinterpret_cast<char*>(m_desc.m_memoryBlock)));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Allocate
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapSchema::pointer_type
|
||||
BestFitExternalMapSchema::Allocate(size_type byteSize, size_type alignment, int flags)
|
||||
{
|
||||
(void)flags;
|
||||
char* address = nullptr;
|
||||
AZ_Assert(alignment > 0 && (alignment & (alignment - 1)) == 0, "Alignment must be >0 and power of 2!");
|
||||
for (int i = 0; i < 2; ++i) // max 2 attempts to allocate
|
||||
{
|
||||
FreeMapType::iterator iter = m_freeChunksMap.find(byteSize);
|
||||
size_t blockSize = 0;
|
||||
char* blockAddress = nullptr;
|
||||
size_t preAllocBlockSize = 0;
|
||||
while (iter != m_freeChunksMap.end())
|
||||
if (m_desc.m_mapAllocator == nullptr)
|
||||
{
|
||||
blockSize = iter->first;
|
||||
blockAddress = iter->second;
|
||||
char* alignedAddr = PointerAlignUp(blockAddress, alignment);
|
||||
preAllocBlockSize = alignedAddr - blockAddress;
|
||||
if (preAllocBlockSize + byteSize <= blockSize)
|
||||
{
|
||||
m_freeChunksMap.erase(iter); // we have our allocation
|
||||
m_used += byteSize;
|
||||
address = alignedAddr;
|
||||
m_allocChunksMap.insert(AZStd::make_pair(address, byteSize));
|
||||
break;
|
||||
}
|
||||
++iter;
|
||||
m_desc.m_mapAllocator = &AllocatorInstance<SystemAllocator>::Get(); // used as our sub allocator
|
||||
}
|
||||
if (address != nullptr)
|
||||
AZ_Assert(m_desc.m_memoryBlockByteSize > 0, "You must provide memory block size!");
|
||||
AZ_Assert(m_desc.m_memoryBlock != nullptr, "You must provide memory block allocated as you with!");
|
||||
// if( m_desc.m_memoryBlock == NULL) there is no point to automate this cause we need to flag this memory special, otherwise there
|
||||
// is no point to use this allocator at all
|
||||
// m_desc.m_memoryBlock = azmalloc(SystemAllocator,m_desc.m_memoryBlockByteSize,16);
|
||||
m_freeChunksMap.insert(AZStd::make_pair(m_desc.m_memoryBlockByteSize, reinterpret_cast<char*>(m_desc.m_memoryBlock)));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Allocate
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapSchema::pointer_type BestFitExternalMapSchema::Allocate(size_type byteSize, size_type alignment, int flags)
|
||||
{
|
||||
(void)flags;
|
||||
char* address = nullptr;
|
||||
AZ_Assert(alignment > 0 && (alignment & (alignment - 1)) == 0, "Alignment must be >0 and power of 2!");
|
||||
for (int i = 0; i < 2; ++i) // max 2 attempts to allocate
|
||||
{
|
||||
// split blocks
|
||||
if (preAllocBlockSize) // if we have a block before the alignment
|
||||
FreeMapType::iterator iter = m_freeChunksMap.find(byteSize);
|
||||
size_t blockSize = 0;
|
||||
char* blockAddress = nullptr;
|
||||
size_t preAllocBlockSize = 0;
|
||||
while (iter != m_freeChunksMap.end())
|
||||
{
|
||||
m_freeChunksMap.insert(AZStd::make_pair(preAllocBlockSize, blockAddress));
|
||||
}
|
||||
size_t postAllocBlockSize = blockSize - preAllocBlockSize - byteSize;
|
||||
if (postAllocBlockSize)
|
||||
{
|
||||
m_freeChunksMap.insert(AZStd::make_pair(postAllocBlockSize, address + byteSize));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
GarbageCollect();
|
||||
}
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// DeAllocate
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
void
|
||||
BestFitExternalMapSchema::DeAllocate(pointer_type ptr)
|
||||
{
|
||||
if (ptr == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
AllocMapType::iterator iter = m_allocChunksMap.find(reinterpret_cast<char*>(ptr));
|
||||
if (iter != m_allocChunksMap.end())
|
||||
{
|
||||
m_used -= iter->second;
|
||||
m_freeChunksMap.insert(AZStd::make_pair(iter->second, iter->first));
|
||||
m_allocChunksMap.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// AllocationSize
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapSchema::size_type
|
||||
BestFitExternalMapSchema::AllocationSize(pointer_type ptr)
|
||||
{
|
||||
AllocMapType::iterator iter = m_allocChunksMap.find(reinterpret_cast<char*>(ptr));
|
||||
if (iter != m_allocChunksMap.end())
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// GetMaxAllocationSize
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapSchema::size_type
|
||||
BestFitExternalMapSchema::GetMaxAllocationSize() const
|
||||
{
|
||||
if (!m_freeChunksMap.empty())
|
||||
{
|
||||
return m_freeChunksMap.rbegin()->first;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto BestFitExternalMapSchema::GetMaxContiguousAllocationSize() const -> size_type
|
||||
{
|
||||
// Return the maximum size of any single allocation
|
||||
return AZ_CORE_MAX_ALLOCATOR_SIZE;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// GarbageCollect
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
void
|
||||
BestFitExternalMapSchema::GarbageCollect()
|
||||
{
|
||||
for (FreeMapType::iterator curBlock = m_freeChunksMap.begin(); curBlock != m_freeChunksMap.end(); )
|
||||
{
|
||||
char* curStart = curBlock->second;
|
||||
char* curEnd = curStart + curBlock->first;
|
||||
bool isMerge = false;
|
||||
for (FreeMapType::iterator nextBlock = curBlock++; nextBlock != m_freeChunksMap.end(); )
|
||||
{
|
||||
char* nextStart = nextBlock->second;
|
||||
char* nextEnd = nextStart + nextBlock->first;
|
||||
if (curStart == nextEnd)
|
||||
{
|
||||
// merge
|
||||
size_t newBlockSize = curBlock->first + nextBlock->first;
|
||||
char* newBlockAddress = nextStart;
|
||||
m_freeChunksMap.erase(nextBlock);
|
||||
FreeMapType::iterator toErase = curBlock;
|
||||
++curBlock;
|
||||
m_freeChunksMap.erase(toErase);
|
||||
FreeMapType::iterator newBlock = m_freeChunksMap.insert(AZStd::make_pair(newBlockSize, newBlockAddress)).first;
|
||||
if (curBlock != m_freeChunksMap.end() && newBlockSize < curBlock->first) // if the newBlock in before the next in the list, update next in the list to current
|
||||
blockSize = iter->first;
|
||||
blockAddress = iter->second;
|
||||
char* alignedAddr = PointerAlignUp(blockAddress, alignment);
|
||||
preAllocBlockSize = alignedAddr - blockAddress;
|
||||
if (preAllocBlockSize + byteSize <= blockSize)
|
||||
{
|
||||
curBlock = newBlock;
|
||||
m_freeChunksMap.erase(iter); // we have our allocation
|
||||
m_used += byteSize;
|
||||
address = alignedAddr;
|
||||
m_allocChunksMap.insert(AZStd::make_pair(address, byteSize));
|
||||
break;
|
||||
}
|
||||
isMerge = true;
|
||||
break;
|
||||
++iter;
|
||||
}
|
||||
else if (curEnd == nextStart)
|
||||
if (address != nullptr)
|
||||
{
|
||||
// merge
|
||||
size_t newBlockSize = curBlock->first + nextBlock->first;
|
||||
char* newBlockAddress = curStart;
|
||||
m_freeChunksMap.erase(nextBlock);
|
||||
FreeMapType::iterator toErase = curBlock;
|
||||
++curBlock;
|
||||
m_freeChunksMap.erase(toErase);
|
||||
FreeMapType::iterator newBlock = m_freeChunksMap.insert(AZStd::make_pair(newBlockSize, newBlockAddress)).first;
|
||||
if (curBlock != m_freeChunksMap.end() && newBlockSize < curBlock->first) // if the newBlock in before the next in the list, update next in the list to current
|
||||
// split blocks
|
||||
if (preAllocBlockSize) // if we have a block before the alignment
|
||||
{
|
||||
curBlock = newBlock;
|
||||
m_freeChunksMap.insert(AZStd::make_pair(preAllocBlockSize, blockAddress));
|
||||
}
|
||||
isMerge = true;
|
||||
size_t postAllocBlockSize = blockSize - preAllocBlockSize - byteSize;
|
||||
if (postAllocBlockSize)
|
||||
{
|
||||
m_freeChunksMap.insert(AZStd::make_pair(postAllocBlockSize, address + byteSize));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
++nextBlock;
|
||||
else
|
||||
{
|
||||
GarbageCollect();
|
||||
}
|
||||
}
|
||||
if (!isMerge)
|
||||
return address;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// DeAllocate
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
void BestFitExternalMapSchema::DeAllocate(pointer_type ptr)
|
||||
{
|
||||
if (ptr == nullptr)
|
||||
{
|
||||
++curBlock;
|
||||
return;
|
||||
}
|
||||
AllocMapType::iterator iter = m_allocChunksMap.find(reinterpret_cast<char*>(ptr));
|
||||
if (iter != m_allocChunksMap.end())
|
||||
{
|
||||
m_used -= iter->second;
|
||||
m_freeChunksMap.insert(AZStd::make_pair(iter->second, iter->first));
|
||||
m_allocChunksMap.erase(iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// AllocationSize
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapSchema::size_type BestFitExternalMapSchema::AllocationSize(pointer_type ptr)
|
||||
{
|
||||
AllocMapType::iterator iter = m_allocChunksMap.find(reinterpret_cast<char*>(ptr));
|
||||
if (iter != m_allocChunksMap.end())
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// GetMaxAllocationSize
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapSchema::size_type BestFitExternalMapSchema::GetMaxAllocationSize() const
|
||||
{
|
||||
if (!m_freeChunksMap.empty())
|
||||
{
|
||||
return m_freeChunksMap.rbegin()->first;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto BestFitExternalMapSchema::GetMaxContiguousAllocationSize() const -> size_type
|
||||
{
|
||||
// Return the maximum size of any single allocation
|
||||
return AZ_CORE_MAX_ALLOCATOR_SIZE;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// GarbageCollect
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
void BestFitExternalMapSchema::GarbageCollect()
|
||||
{
|
||||
for (FreeMapType::iterator curBlock = m_freeChunksMap.begin(); curBlock != m_freeChunksMap.end();)
|
||||
{
|
||||
char* curStart = curBlock->second;
|
||||
char* curEnd = curStart + curBlock->first;
|
||||
bool isMerge = false;
|
||||
for (FreeMapType::iterator nextBlock = curBlock++; nextBlock != m_freeChunksMap.end();)
|
||||
{
|
||||
char* nextStart = nextBlock->second;
|
||||
char* nextEnd = nextStart + nextBlock->first;
|
||||
if (curStart == nextEnd)
|
||||
{
|
||||
// merge
|
||||
size_t newBlockSize = curBlock->first + nextBlock->first;
|
||||
char* newBlockAddress = nextStart;
|
||||
m_freeChunksMap.erase(nextBlock);
|
||||
FreeMapType::iterator toErase = curBlock;
|
||||
++curBlock;
|
||||
m_freeChunksMap.erase(toErase);
|
||||
FreeMapType::iterator newBlock = m_freeChunksMap.insert(AZStd::make_pair(newBlockSize, newBlockAddress)).first;
|
||||
// if the newBlock in before the next in the list, update next in the list to current
|
||||
if (curBlock != m_freeChunksMap.end() && newBlockSize < curBlock->first)
|
||||
{
|
||||
curBlock = newBlock;
|
||||
}
|
||||
isMerge = true;
|
||||
break;
|
||||
}
|
||||
else if (curEnd == nextStart)
|
||||
{
|
||||
// merge
|
||||
size_t newBlockSize = curBlock->first + nextBlock->first;
|
||||
char* newBlockAddress = curStart;
|
||||
m_freeChunksMap.erase(nextBlock);
|
||||
FreeMapType::iterator toErase = curBlock;
|
||||
++curBlock;
|
||||
m_freeChunksMap.erase(toErase);
|
||||
FreeMapType::iterator newBlock = m_freeChunksMap.insert(AZStd::make_pair(newBlockSize, newBlockAddress)).first;
|
||||
// if the newBlock in before the next in the list, update next in the list to current
|
||||
if (curBlock != m_freeChunksMap.end() && newBlockSize < curBlock->first)
|
||||
{
|
||||
curBlock = newBlock;
|
||||
}
|
||||
isMerge = true;
|
||||
break;
|
||||
}
|
||||
++nextBlock;
|
||||
}
|
||||
if (!isMerge)
|
||||
{
|
||||
++curBlock;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace AZ
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#ifndef AZ_BEST_FIT_EXT_MAP_ALLOCATION_SCHEME_H
|
||||
#define AZ_BEST_FIT_EXT_MAP_ALLOCATION_SCHEME_H
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Memory/Memory.h>
|
||||
@@ -77,8 +76,3 @@ namespace AZ
|
||||
AllocMapType m_allocChunksMap;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // AZ_BEST_FIT_EXT_MAP_ALLOCATION_SCHEME_H
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,8 +5,7 @@
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#ifndef AZ_POOL_ALLOCATION_SCHEME_H
|
||||
#define AZ_POOL_ALLOCATION_SCHEME_H
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
|
||||
@@ -164,8 +163,3 @@ namespace AZ
|
||||
template<class Allocator>
|
||||
AZ_THREAD_LOCAL ThreadPoolData* ThreadPoolSchemaHelper<Allocator>::m_threadData = 0;
|
||||
}
|
||||
|
||||
#endif // AZ_POOL_ALLOCATION_SCHEME_H
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
#define AZCORE_SYSTEM_ALLOCATOR_HEAP 3
|
||||
|
||||
#if !defined(AZCORE_SYSTEM_ALLOCATOR)
|
||||
// define the default
|
||||
#define AZCORE_SYSTEM_ALLOCATOR AZCORE_SYSTEM_ALLOCATOR_HPHA
|
||||
// define the default
|
||||
#define AZCORE_SYSTEM_ALLOCATOR AZCORE_SYSTEM_ALLOCATOR_HPHA
|
||||
#endif
|
||||
|
||||
#if AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HPHA
|
||||
@@ -35,12 +35,11 @@
|
||||
#error "Invalid allocator selected for SystemAllocator"
|
||||
#endif
|
||||
|
||||
|
||||
using namespace AZ;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Globals - we use global storage for the first memory schema, since we can't use dynamic memory!
|
||||
static bool g_isSystemSchemaUsed = false;
|
||||
namespace AZ
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Globals - we use global storage for the first memory schema, since we can't use dynamic memory!
|
||||
static bool g_isSystemSchemaUsed = false;
|
||||
#if AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HPHA
|
||||
static AZStd::aligned_storage<sizeof(HphaSchema), AZStd::alignment_of<HphaSchema>::value>::type g_systemSchema;
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_MALLOC
|
||||
@@ -49,268 +48,275 @@ static bool g_isSystemSchemaUsed = false;
|
||||
static AZStd::aligned_storage<sizeof(HeapSchema), AZStd::alignment_of<HeapSchema>::value>::type g_systemSchema;
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//=========================================================================
|
||||
// SystemAllocator
|
||||
// [9/2/2009]
|
||||
//=========================================================================
|
||||
SystemAllocator::SystemAllocator()
|
||||
: AllocatorBase(this, "SystemAllocator", "Fundamental generic memory allocator")
|
||||
, m_isCustom(false)
|
||||
, m_allocator(nullptr)
|
||||
, m_ownsOSAllocator(false)
|
||||
{
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ~SystemAllocator
|
||||
//=========================================================================
|
||||
SystemAllocator::~SystemAllocator()
|
||||
{
|
||||
if (IsReady())
|
||||
//=========================================================================
|
||||
// SystemAllocator
|
||||
// [9/2/2009]
|
||||
//=========================================================================
|
||||
SystemAllocator::SystemAllocator()
|
||||
: AllocatorBase(this, "SystemAllocator", "Fundamental generic memory allocator")
|
||||
, m_isCustom(false)
|
||||
, m_allocator(nullptr)
|
||||
, m_ownsOSAllocator(false)
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ~Create
|
||||
// [9/2/2009]
|
||||
//=========================================================================
|
||||
bool
|
||||
SystemAllocator::Create(const Descriptor& desc)
|
||||
{
|
||||
AZ_Assert(IsReady() == false, "System allocator was already created!");
|
||||
if (IsReady())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_desc = desc;
|
||||
|
||||
if (!AllocatorInstance<OSAllocator>::IsReady())
|
||||
//=========================================================================
|
||||
// ~SystemAllocator
|
||||
//=========================================================================
|
||||
SystemAllocator::~SystemAllocator()
|
||||
{
|
||||
m_ownsOSAllocator = true;
|
||||
AllocatorInstance<OSAllocator>::Create();
|
||||
}
|
||||
bool isReady = false;
|
||||
if (desc.m_custom)
|
||||
{
|
||||
m_isCustom = true;
|
||||
m_allocator = desc.m_custom;
|
||||
isReady = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_isCustom = false;
|
||||
#if AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HPHA
|
||||
HphaSchema::Descriptor heapDesc;
|
||||
heapDesc.m_pageSize = desc.m_heap.m_pageSize;
|
||||
heapDesc.m_poolPageSize = desc.m_heap.m_poolPageSize;
|
||||
AZ_Assert(desc.m_heap.m_numFixedMemoryBlocks <= 1, "We support max1 memory block at the moment!");
|
||||
if (desc.m_heap.m_numFixedMemoryBlocks > 0)
|
||||
if (IsReady())
|
||||
{
|
||||
heapDesc.m_fixedMemoryBlock = desc.m_heap.m_fixedMemoryBlocks[0];
|
||||
heapDesc.m_fixedMemoryBlockByteSize = desc.m_heap.m_fixedMemoryBlocksByteSize[0];
|
||||
Destroy();
|
||||
}
|
||||
heapDesc.m_subAllocator = desc.m_heap.m_subAllocator;
|
||||
heapDesc.m_isPoolAllocations = desc.m_heap.m_isPoolAllocations;
|
||||
// Fix SystemAllocator from growing in small chunks
|
||||
heapDesc.m_systemChunkSize = desc.m_heap.m_systemChunkSize;
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_MALLOC
|
||||
MallocSchema::Descriptor heapDesc;
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HEAP
|
||||
HeapSchema::Descriptor heapDesc;
|
||||
memcpy(heapDesc.m_memoryBlocks, desc.m_heap.m_memoryBlocks, sizeof(heapDesc.m_memoryBlocks));
|
||||
memcpy(heapDesc.m_memoryBlocksByteSize, desc.m_heap.m_memoryBlocksByteSize, sizeof(heapDesc.m_memoryBlocksByteSize));
|
||||
heapDesc.m_numMemoryBlocks = desc.m_heap.m_numMemoryBlocks;
|
||||
#endif
|
||||
if (&AllocatorInstance<SystemAllocator>::Get() == this) // if we are the system allocator
|
||||
{
|
||||
AZ_Assert(!g_isSystemSchemaUsed, "AZ::SystemAllocator MUST be created first! It's the source of all allocations!");
|
||||
}
|
||||
|
||||
#if AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HPHA
|
||||
m_allocator = new(&g_systemSchema)HphaSchema(heapDesc);
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_MALLOC
|
||||
m_allocator = new(&g_systemSchema)MallocSchema(heapDesc);
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HEAP
|
||||
m_allocator = new(&g_systemSchema)HeapSchema(heapDesc);
|
||||
#endif
|
||||
g_isSystemSchemaUsed = true;
|
||||
//=========================================================================
|
||||
// ~Create
|
||||
// [9/2/2009]
|
||||
//=========================================================================
|
||||
bool SystemAllocator::Create(const Descriptor& desc)
|
||||
{
|
||||
AZ_Assert(IsReady() == false, "System allocator was already created!");
|
||||
if (IsReady())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_desc = desc;
|
||||
|
||||
if (!AllocatorInstance<OSAllocator>::IsReady())
|
||||
{
|
||||
m_ownsOSAllocator = true;
|
||||
AllocatorInstance<OSAllocator>::Create();
|
||||
}
|
||||
bool isReady = false;
|
||||
if (desc.m_custom)
|
||||
{
|
||||
m_isCustom = true;
|
||||
m_allocator = desc.m_custom;
|
||||
isReady = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// this class should be inheriting from SystemAllocator
|
||||
AZ_Assert(AllocatorInstance<SystemAllocator>::IsReady(), "System allocator must be created before any other allocator! They allocate from it.");
|
||||
m_isCustom = false;
|
||||
#if AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HPHA
|
||||
HphaSchema::Descriptor heapDesc;
|
||||
heapDesc.m_pageSize = desc.m_heap.m_pageSize;
|
||||
heapDesc.m_poolPageSize = desc.m_heap.m_poolPageSize;
|
||||
AZ_Assert(desc.m_heap.m_numFixedMemoryBlocks <= 1, "We support max1 memory block at the moment!");
|
||||
if (desc.m_heap.m_numFixedMemoryBlocks > 0)
|
||||
{
|
||||
heapDesc.m_fixedMemoryBlock = desc.m_heap.m_fixedMemoryBlocks[0];
|
||||
heapDesc.m_fixedMemoryBlockByteSize = desc.m_heap.m_fixedMemoryBlocksByteSize[0];
|
||||
}
|
||||
heapDesc.m_subAllocator = desc.m_heap.m_subAllocator;
|
||||
heapDesc.m_isPoolAllocations = desc.m_heap.m_isPoolAllocations;
|
||||
// Fix SystemAllocator from growing in small chunks
|
||||
heapDesc.m_systemChunkSize = desc.m_heap.m_systemChunkSize;
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_MALLOC
|
||||
MallocSchema::Descriptor heapDesc;
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HEAP
|
||||
HeapSchema::Descriptor heapDesc;
|
||||
memcpy(heapDesc.m_memoryBlocks, desc.m_heap.m_memoryBlocks, sizeof(heapDesc.m_memoryBlocks));
|
||||
memcpy(heapDesc.m_memoryBlocksByteSize, desc.m_heap.m_memoryBlocksByteSize, sizeof(heapDesc.m_memoryBlocksByteSize));
|
||||
heapDesc.m_numMemoryBlocks = desc.m_heap.m_numMemoryBlocks;
|
||||
#endif
|
||||
if (&AllocatorInstance<SystemAllocator>::Get() == this) // if we are the system allocator
|
||||
{
|
||||
AZ_Assert(!g_isSystemSchemaUsed, "AZ::SystemAllocator MUST be created first! It's the source of all allocations!");
|
||||
|
||||
#if AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HPHA
|
||||
m_allocator = azcreate(HphaSchema, (heapDesc), SystemAllocator);
|
||||
m_allocator = new (&g_systemSchema) HphaSchema(heapDesc);
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_MALLOC
|
||||
m_allocator = azcreate(MallocSchema, (heapDesc), SystemAllocator);
|
||||
m_allocator = new (&g_systemSchema) MallocSchema(heapDesc);
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HEAP
|
||||
m_allocator = azcreate(HeapSchema, (heapDesc), SystemAllocator);
|
||||
m_allocator = new (&g_systemSchema) HeapSchema(heapDesc);
|
||||
#endif
|
||||
if (m_allocator == nullptr)
|
||||
{
|
||||
isReady = false;
|
||||
g_isSystemSchemaUsed = true;
|
||||
isReady = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
isReady = true;
|
||||
// this class should be inheriting from SystemAllocator
|
||||
AZ_Assert(
|
||||
AllocatorInstance<SystemAllocator>::IsReady(),
|
||||
"System allocator must be created before any other allocator! They allocate from it.");
|
||||
|
||||
#if AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HPHA
|
||||
m_allocator = azcreate(HphaSchema, (heapDesc), SystemAllocator);
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_MALLOC
|
||||
m_allocator = azcreate(MallocSchema, (heapDesc), SystemAllocator);
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HEAP
|
||||
m_allocator = azcreate(HeapSchema, (heapDesc), SystemAllocator);
|
||||
#endif
|
||||
if (m_allocator == nullptr)
|
||||
{
|
||||
isReady = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
isReady = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return isReady;
|
||||
}
|
||||
|
||||
return isReady;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Allocate
|
||||
// [9/2/2009]
|
||||
//=========================================================================
|
||||
void
|
||||
SystemAllocator::Destroy()
|
||||
{
|
||||
if (g_isSystemSchemaUsed)
|
||||
//=========================================================================
|
||||
// Allocate
|
||||
// [9/2/2009]
|
||||
//=========================================================================
|
||||
void SystemAllocator::Destroy()
|
||||
{
|
||||
int dummy;
|
||||
(void)dummy;
|
||||
}
|
||||
|
||||
if (!m_isCustom)
|
||||
{
|
||||
if ((void*)m_allocator == (void*)&g_systemSchema)
|
||||
if (g_isSystemSchemaUsed)
|
||||
{
|
||||
int dummy;
|
||||
(void)dummy;
|
||||
}
|
||||
|
||||
if (!m_isCustom)
|
||||
{
|
||||
if ((void*)m_allocator == (void*)&g_systemSchema)
|
||||
{
|
||||
#if AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HPHA
|
||||
static_cast<HphaSchema*>(m_allocator)->~HphaSchema();
|
||||
static_cast<HphaSchema*>(m_allocator)->~HphaSchema();
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_MALLOC
|
||||
static_cast<MallocSchema*>(m_allocator)->~MallocSchema();
|
||||
static_cast<MallocSchema*>(m_allocator)->~MallocSchema();
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HEAP
|
||||
static_cast<HeapSchema*>(m_allocator)->~HeapSchema();
|
||||
static_cast<HeapSchema*>(m_allocator)->~HeapSchema();
|
||||
#endif
|
||||
g_isSystemSchemaUsed = false;
|
||||
g_isSystemSchemaUsed = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
azdestroy(m_allocator);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
if (m_ownsOSAllocator)
|
||||
{
|
||||
azdestroy(m_allocator);
|
||||
AllocatorInstance<OSAllocator>::Destroy();
|
||||
m_ownsOSAllocator = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_ownsOSAllocator)
|
||||
AllocatorDebugConfig SystemAllocator::GetDebugConfig()
|
||||
{
|
||||
AllocatorInstance<OSAllocator>::Destroy();
|
||||
m_ownsOSAllocator = false;
|
||||
}
|
||||
}
|
||||
|
||||
AllocatorDebugConfig SystemAllocator::GetDebugConfig()
|
||||
{
|
||||
return AllocatorDebugConfig()
|
||||
.StackRecordLevels(m_desc.m_stackRecordLevels)
|
||||
.UsesMemoryGuards(!m_isCustom)
|
||||
.MarksUnallocatedMemory(!m_isCustom)
|
||||
.ExcludeFromDebugging(!m_desc.m_allocationRecords);
|
||||
}
|
||||
|
||||
IAllocatorAllocate* SystemAllocator::GetSchema()
|
||||
{
|
||||
return m_allocator;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Allocate
|
||||
// [9/2/2009]
|
||||
//=========================================================================
|
||||
SystemAllocator::pointer_type
|
||||
SystemAllocator::Allocate(size_type byteSize, size_type alignment, int flags, const char* name, const char* fileName, int lineNum, unsigned int suppressStackRecord)
|
||||
{
|
||||
if (byteSize == 0)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
AZ_Assert(byteSize > 0, "You can not allocate 0 bytes!");
|
||||
AZ_Assert((alignment & (alignment - 1)) == 0, "Alignment must be power of 2!");
|
||||
|
||||
byteSize = MemorySizeAdjustedUp(byteSize);
|
||||
SystemAllocator::pointer_type address = m_allocator->Allocate(byteSize, alignment, flags, name, fileName, lineNum, suppressStackRecord + 1);
|
||||
|
||||
if (address == nullptr)
|
||||
{
|
||||
// Free all memory we can and try again!
|
||||
AllocatorManager::Instance().GarbageCollect();
|
||||
|
||||
address = m_allocator->Allocate(byteSize, alignment, flags, name, fileName, lineNum, suppressStackRecord + 1);
|
||||
return AllocatorDebugConfig()
|
||||
.StackRecordLevels(m_desc.m_stackRecordLevels)
|
||||
.UsesMemoryGuards(!m_isCustom)
|
||||
.MarksUnallocatedMemory(!m_isCustom)
|
||||
.ExcludeFromDebugging(!m_desc.m_allocationRecords);
|
||||
}
|
||||
|
||||
if (address == nullptr)
|
||||
IAllocatorAllocate* SystemAllocator::GetSchema()
|
||||
{
|
||||
byteSize = MemorySizeAdjustedDown(byteSize); // restore original size
|
||||
return m_allocator;
|
||||
}
|
||||
|
||||
AZ_Assert(address != nullptr, "SystemAllocator: Failed to allocate %d bytes aligned on %d (flags: 0x%08x) %s : %s (%d)!", byteSize, alignment, flags, name ? name : "(no name)", fileName ? fileName : "(no file name)", lineNum);
|
||||
//=========================================================================
|
||||
// Allocate
|
||||
// [9/2/2009]
|
||||
//=========================================================================
|
||||
SystemAllocator::pointer_type SystemAllocator::Allocate(
|
||||
size_type byteSize,
|
||||
size_type alignment,
|
||||
int flags,
|
||||
const char* name,
|
||||
const char* fileName,
|
||||
int lineNum,
|
||||
unsigned int suppressStackRecord)
|
||||
{
|
||||
if (byteSize == 0)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
AZ_Assert(byteSize > 0, "You can not allocate 0 bytes!");
|
||||
AZ_Assert((alignment & (alignment - 1)) == 0, "Alignment must be power of 2!");
|
||||
|
||||
AZ_PROFILE_MEMORY_ALLOC_EX(MemoryReserved, fileName, lineNum, address, byteSize, name);
|
||||
AZ_MEMORY_PROFILE(ProfileAllocation(address, byteSize, alignment, name, fileName, lineNum, suppressStackRecord + 1));
|
||||
byteSize = MemorySizeAdjustedUp(byteSize);
|
||||
SystemAllocator::pointer_type address =
|
||||
m_allocator->Allocate(byteSize, alignment, flags, name, fileName, lineNum, suppressStackRecord + 1);
|
||||
|
||||
return address;
|
||||
}
|
||||
if (address == nullptr)
|
||||
{
|
||||
// Free all memory we can and try again!
|
||||
AllocatorManager::Instance().GarbageCollect();
|
||||
|
||||
//=========================================================================
|
||||
// DeAllocate
|
||||
// [9/2/2009]
|
||||
//=========================================================================
|
||||
void
|
||||
SystemAllocator::DeAllocate(pointer_type ptr, size_type byteSize, size_type alignment)
|
||||
{
|
||||
byteSize = MemorySizeAdjustedUp(byteSize);
|
||||
AZ_PROFILE_MEMORY_FREE(MemoryReserved, ptr);
|
||||
AZ_MEMORY_PROFILE(ProfileDeallocation(ptr, byteSize, alignment, nullptr));
|
||||
m_allocator->DeAllocate(ptr, byteSize, alignment);
|
||||
}
|
||||
address = m_allocator->Allocate(byteSize, alignment, flags, name, fileName, lineNum, suppressStackRecord + 1);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ReAllocate
|
||||
// [9/13/2011]
|
||||
//=========================================================================
|
||||
SystemAllocator::pointer_type
|
||||
SystemAllocator::ReAllocate(pointer_type ptr, size_type newSize, size_type newAlignment)
|
||||
{
|
||||
newSize = MemorySizeAdjustedUp(newSize);
|
||||
if (address == nullptr)
|
||||
{
|
||||
byteSize = MemorySizeAdjustedDown(byteSize); // restore original size
|
||||
}
|
||||
|
||||
AZ_MEMORY_PROFILE(ProfileReallocationBegin(ptr, newSize));
|
||||
AZ_PROFILE_MEMORY_FREE(MemoryReserved, ptr);
|
||||
pointer_type newAddress = m_allocator->ReAllocate(ptr, newSize, newAlignment);
|
||||
AZ_PROFILE_MEMORY_ALLOC(MemoryReserved, newAddress, newSize, "SystemAllocator realloc");
|
||||
AZ_MEMORY_PROFILE(ProfileReallocationEnd(ptr, newAddress, newSize, newAlignment));
|
||||
AZ_Assert(
|
||||
address != nullptr, "SystemAllocator: Failed to allocate %d bytes aligned on %d (flags: 0x%08x) %s : %s (%d)!", byteSize,
|
||||
alignment, flags, name ? name : "(no name)", fileName ? fileName : "(no file name)", lineNum);
|
||||
|
||||
return newAddress;
|
||||
}
|
||||
AZ_PROFILE_MEMORY_ALLOC_EX(MemoryReserved, fileName, lineNum, address, byteSize, name);
|
||||
AZ_MEMORY_PROFILE(ProfileAllocation(address, byteSize, alignment, name, fileName, lineNum, suppressStackRecord + 1));
|
||||
|
||||
//=========================================================================
|
||||
// Resize
|
||||
// [8/12/2011]
|
||||
//=========================================================================
|
||||
SystemAllocator::size_type
|
||||
SystemAllocator::Resize(pointer_type ptr, size_type newSize)
|
||||
{
|
||||
newSize = MemorySizeAdjustedUp(newSize);
|
||||
size_type resizedSize = m_allocator->Resize(ptr, newSize);
|
||||
return address;
|
||||
}
|
||||
|
||||
AZ_MEMORY_PROFILE(ProfileResize(ptr, resizedSize));
|
||||
//=========================================================================
|
||||
// DeAllocate
|
||||
// [9/2/2009]
|
||||
//=========================================================================
|
||||
void SystemAllocator::DeAllocate(pointer_type ptr, size_type byteSize, size_type alignment)
|
||||
{
|
||||
byteSize = MemorySizeAdjustedUp(byteSize);
|
||||
AZ_PROFILE_MEMORY_FREE(MemoryReserved, ptr);
|
||||
AZ_MEMORY_PROFILE(ProfileDeallocation(ptr, byteSize, alignment, nullptr));
|
||||
m_allocator->DeAllocate(ptr, byteSize, alignment);
|
||||
}
|
||||
|
||||
return MemorySizeAdjustedDown(resizedSize);
|
||||
}
|
||||
//=========================================================================
|
||||
// ReAllocate
|
||||
// [9/13/2011]
|
||||
//=========================================================================
|
||||
SystemAllocator::pointer_type SystemAllocator::ReAllocate(pointer_type ptr, size_type newSize, size_type newAlignment)
|
||||
{
|
||||
newSize = MemorySizeAdjustedUp(newSize);
|
||||
|
||||
//=========================================================================
|
||||
//
|
||||
// [8/12/2011]
|
||||
//=========================================================================
|
||||
SystemAllocator::size_type
|
||||
SystemAllocator::AllocationSize(pointer_type ptr)
|
||||
{
|
||||
size_type allocSize = MemorySizeAdjustedDown(m_allocator->AllocationSize(ptr));
|
||||
AZ_MEMORY_PROFILE(ProfileReallocationBegin(ptr, newSize));
|
||||
AZ_PROFILE_MEMORY_FREE(MemoryReserved, ptr);
|
||||
pointer_type newAddress = m_allocator->ReAllocate(ptr, newSize, newAlignment);
|
||||
AZ_PROFILE_MEMORY_ALLOC(MemoryReserved, newAddress, newSize, "SystemAllocator realloc");
|
||||
AZ_MEMORY_PROFILE(ProfileReallocationEnd(ptr, newAddress, newSize, newAlignment));
|
||||
|
||||
return allocSize;
|
||||
}
|
||||
return newAddress;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Resize
|
||||
// [8/12/2011]
|
||||
//=========================================================================
|
||||
SystemAllocator::size_type SystemAllocator::Resize(pointer_type ptr, size_type newSize)
|
||||
{
|
||||
newSize = MemorySizeAdjustedUp(newSize);
|
||||
size_type resizedSize = m_allocator->Resize(ptr, newSize);
|
||||
|
||||
AZ_MEMORY_PROFILE(ProfileResize(ptr, resizedSize));
|
||||
|
||||
return MemorySizeAdjustedDown(resizedSize);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
//
|
||||
// [8/12/2011]
|
||||
//=========================================================================
|
||||
SystemAllocator::size_type SystemAllocator::AllocationSize(pointer_type ptr)
|
||||
{
|
||||
size_type allocSize = MemorySizeAdjustedDown(m_allocator->AllocationSize(ptr));
|
||||
|
||||
return allocSize;
|
||||
}
|
||||
|
||||
} // namespace AZ
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#ifndef AZCORE_SYS_ALLOCATOR_H
|
||||
#define AZCORE_SYS_ALLOCATOR_H
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Memory/Memory.h>
|
||||
|
||||
@@ -120,7 +119,5 @@ namespace AZ
|
||||
};
|
||||
}
|
||||
|
||||
#endif // AZCORE_SYS_ALLOCATOR_H
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user