changes from az

Output now collates issues together into 1 entry for each leak point
tDictionary leak
This commit is contained in:
marauder2k7 2025-05-05 08:17:45 +01:00
parent 1050cad372
commit b0eb3875c9
3 changed files with 95 additions and 28 deletions

View file

@ -193,7 +193,7 @@ private:
{ {
Node* mNext; Node* mNext;
Pair mPair; Pair mPair;
Node(): mNext(0) {} Node(): mNext(nullptr) {}
Node(Pair p,Node* n) Node(Pair p,Node* n)
: mNext(n), : mNext(n),
mPair(p) mPair(p)
@ -226,8 +226,8 @@ public:
_Iterator() _Iterator()
{ {
mHashTable = 0; mHashTable = nullptr;
mLink = 0; mLink = nullptr;
} }
_Iterator(M* table,E* ptr) _Iterator(M* table,E* ptr)
@ -320,7 +320,7 @@ public:
template<typename Key, typename Value> HashTable<Key,Value>::HashTable() : mNodeAllocator(512) template<typename Key, typename Value> HashTable<Key,Value>::HashTable() : mNodeAllocator(512)
{ {
mTableSize = 0; mTableSize = 0;
mTable = 0; mTable = nullptr;
mSize = 0; mSize = 0;
} }
@ -328,7 +328,7 @@ template<typename Key, typename Value> HashTable<Key,Value>::HashTable(const Has
{ {
mSize = 0; mSize = 0;
mTableSize = 0; mTableSize = 0;
mTable = 0; mTable = nullptr;
*this = p; *this = p;
} }
@ -357,7 +357,7 @@ typename HashTable<Key,Value>::Node* HashTable<Key,Value>::_next(U32 index) cons
for (; index < mTableSize; index++) for (; index < mTableSize; index++)
if (Node* node = mTable[index]) if (Node* node = mTable[index])
return node; return node;
return 0; return nullptr;
} }
template<typename Key, typename Value> template<typename Key, typename Value>
@ -402,7 +402,7 @@ void HashTable<Key,Value>::_destroy()
mNodeAllocator.freeBlocks(); mNodeAllocator.freeBlocks();
delete[] mTable; delete[] mTable;
mTable = NULL; mTable = nullptr;
} }
@ -509,7 +509,7 @@ typename HashTable<Key,Value>::Iterator HashTable<Key,Value>::insertEqual(const
template<typename Key, typename Value> template<typename Key, typename Value>
void HashTable<Key,Value>::erase(const Key& key) void HashTable<Key,Value>::erase(const Key& key)
{ {
if (mTable==NULL) if (mTable == nullptr)
return; return;
Node** prev = &mTable[_index(key)]; Node** prev = &mTable[_index(key)];
for (Node* itr = *prev; itr; prev = &itr->mNext, itr = itr->mNext) for (Node* itr = *prev; itr; prev = &itr->mNext, itr = itr->mNext)
@ -529,7 +529,7 @@ void HashTable<Key,Value>::erase(const Key& key)
template<typename Key, typename Value> template<typename Key, typename Value>
void HashTable<Key,Value>::erase(Iterator node) void HashTable<Key,Value>::erase(Iterator node)
{ {
if (mTable==NULL) if (mTable == nullptr)
return; return;
Node** prev = &mTable[_index(node->key)]; Node** prev = &mTable[_index(node->key)];
for (Node* itr = *prev; itr; prev = &itr->mNext, itr = itr->mNext) for (Node* itr = *prev; itr; prev = &itr->mNext, itr = itr->mNext)
@ -547,7 +547,7 @@ void HashTable<Key,Value>::erase(Iterator node)
template<typename Key, typename Value> template<typename Key, typename Value>
void HashTable<Key,Value>::erase(const Key & key, const Value & value) void HashTable<Key,Value>::erase(const Key & key, const Value & value)
{ {
if (mTable==NULL) if (mTable == nullptr)
return; return;
Node** prev = &mTable[_index(key)]; Node** prev = &mTable[_index(key)];
for (Node* itr = *prev; itr; prev = &itr->mNext, itr = itr->mNext) for (Node* itr = *prev; itr; prev = &itr->mNext, itr = itr->mNext)
@ -591,7 +591,7 @@ typename HashTable<Key,Value>::Iterator HashTable<Key,Value>::find(const Key& ke
for (Node* itr = mTable[_index(key)]; itr; itr = itr->mNext) for (Node* itr = mTable[_index(key)]; itr; itr = itr->mNext)
if ( KeyCmp::equals<Key>( itr->mPair.key, key ) ) if ( KeyCmp::equals<Key>( itr->mPair.key, key ) )
return Iterator(this,itr); return Iterator(this,itr);
return Iterator(this,0); return Iterator(this, nullptr);
} }
template<typename Key, typename Value> template<typename Key, typename Value>
@ -605,7 +605,7 @@ typename HashTable<Key,Value>::ConstIterator HashTable<Key,Value>::find(const Ke
return ConstIterator(this,itr); return ConstIterator(this,itr);
} }
} }
return ConstIterator(this,0); return ConstIterator(this, nullptr);
} }
template<typename Key, typename Value> template<typename Key, typename Value>
@ -659,13 +659,13 @@ inline typename HashTable<Key,Value>::ConstIterator HashTable<Key,Value>::begin(
template<typename Key, typename Value> template<typename Key, typename Value>
inline typename HashTable<Key,Value>::Iterator HashTable<Key,Value>::end() inline typename HashTable<Key,Value>::Iterator HashTable<Key,Value>::end()
{ {
return Iterator(this,0); return Iterator(this, nullptr);
} }
template<typename Key, typename Value> template<typename Key, typename Value>
inline typename HashTable<Key,Value>::ConstIterator HashTable<Key,Value>::end() const inline typename HashTable<Key,Value>::ConstIterator HashTable<Key,Value>::end() const
{ {
return ConstIterator(this,0); return ConstIterator(this, nullptr);
} }

View file

@ -38,6 +38,7 @@
#include <execinfo.h> #include <execinfo.h>
#endif #endif
#include <ctime> #include <ctime>
#include <string>
// If profile paths are enabled, disable profiling of the // If profile paths are enabled, disable profiling of the
// memory manager as that would cause a cyclic dependency // memory manager as that would cause a cyclic dependency
@ -75,7 +76,16 @@ namespace Memory
static U32 currentAllocId = 0; static U32 currentAllocId = 0;
static bool initialized = false; static bool initialized = false;
char gLogFilename[256] = { 0 }; char gLogFilename[256] = { 0 };
bool gStackTrace = false; bool gStackTrace = true;
bool gFromScript = false;
struct memReport
{
std::string report;
bool skip;
U32 count = 1;
U32 total = 0;
} memLog[MaxAllocs];
void init() void init()
{ {
@ -100,16 +110,27 @@ namespace Memory
return; return;
std::fprintf(log, "\n--- Memory Leak Report ---\n"); std::fprintf(log, "\n--- Memory Leak Report ---\n");
for (U32 i = 0; i < allocCount; ++i)
U32 start = 0;
U32 stop = allocCount;
if (gFromScript) //filter out the bits from console
{ {
if (allocList[i].ptr != nullptr) start = 6;
stop = allocCount - 8;
}
for (U32 curRep = start; curRep < stop; ++curRep)
{
if (allocList[curRep].ptr != nullptr)
{ {
std::fprintf(log, "Leak: %p (%zu bytes) from %s:%u [id=%u]\n", char entry[512] = "";
allocList[i].ptr, allocList[i].size, std::sprintf(entry, "from %s:%u\n", allocList[curRep].file ? allocList[curRep].file : "(null)", allocList[curRep].line);
allocList[i].file ? allocList[i].file : "(null)", allocList[i].line,
allocList[i].allocId); memLog[curRep].skip = false;
std::string report = entry;
if (gStackTrace) if (gStackTrace)
{ {
char stack[512] = "";
#ifdef _WIN32 #ifdef _WIN32
SYMBOL_INFO* symbol = (SYMBOL_INFO*)malloc(sizeof(SYMBOL_INFO) + 256); SYMBOL_INFO* symbol = (SYMBOL_INFO*)malloc(sizeof(SYMBOL_INFO) + 256);
symbol->MaxNameLen = 255; symbol->MaxNameLen = 255;
@ -118,31 +139,67 @@ namespace Memory
HANDLE process = GetCurrentProcess(); HANDLE process = GetCurrentProcess();
SymInitialize(process, NULL, TRUE); SymInitialize(process, NULL, TRUE);
for (int j = 0; j < allocList[i].backtraceSize; ++j) for (int curStack = 0; curStack < allocList[curRep].backtraceSize; ++curStack)
{ {
DWORD64 addr = (DWORD64)(allocList[i].backtracePtrs[j]); DWORD64 addr = (DWORD64)(allocList[curRep].backtracePtrs[curStack]);
if (SymFromAddr(process, addr, 0, symbol)) if (SymFromAddr(process, addr, 0, symbol))
{ {
std::fprintf(log, " [%d] %s - 0x%0llX\n", j, symbol->Name, symbol->Address); std::sprintf(stack, " [%d] %s - 0x%0llX\n", curStack, symbol->Name, symbol->Address);
} }
else else
{ {
std::fprintf(log, " [%d] ??? - 0x%0llX\n", j, addr); std::sprintf(stack, " [%d] ??? - 0x%0llX\n", curStack, addr);
} }
report += stack;
} }
std::free(symbol); std::free(symbol);
#else #else
char** symbols = backtrace_symbols(allocList[i].backtracePtrs, allocList[i].backtraceSize); char** symbols = backtrace_symbols(allocList[curRep].backtracePtrs, allocList[i].backtraceSize);
for (int j = 0; j < allocList[i].backtraceSize; ++j) for (int curStack = 0; curStack < allocList[curRep].backtraceSize; ++curStack)
{ {
std::fprintf(log, " [%d] %s\n", j, symbols[j]); std::sprintf(stack, " [%d] %s\n", curStack, symbols[curStack]);
report += stack;
} }
std::free(symbols); std::free(symbols);
#endif #endif
} }
if (report.find("getDocsLink") != std::string::npos)
{
//known issue. one off allocation
memLog[curRep].skip = true;
}
for (U32 oldRep = start; oldRep < curRep; ++oldRep)
{
if (!memLog[oldRep].skip && (memLog[oldRep].report.find(report) != std::string::npos))
{
//inc origional
memLog[oldRep].count++;
memLog[oldRep].total += allocList[curRep].size;
//skip dupe report
memLog[curRep].skip = true;
}
}
if (!memLog[curRep].skip)
{
memLog[curRep].report = report;
memLog[curRep].count = 1;
memLog[curRep].total = allocList[curRep].size;
}
} }
} }
for (U32 ntry = start; ntry < stop; ++ntry)
{
if (!memLog[ntry].skip)
{
std::fprintf(log, "Leak-count[%i]total[%i]:%s", memLog[ntry].count, memLog[ntry].total, memLog[ntry].report.c_str());
memLog[ntry].report.clear();
}
}
std::fclose(log); std::fclose(log);
initialized = false; initialized = false;
} }
@ -341,6 +398,14 @@ void* dRealloc_r(void* in_pResize, dsize_t in_size, const char* fileName, const
return Memory::realloc(in_pResize, in_size, fileName, line); return Memory::realloc(in_pResize, in_size, fileName, line);
} }
DefineEngineFunction(LeakTrace, void, (bool start, bool stackTrace), (true, true), "start/stop tracing leaks")
{
if (Memory::initialized) Memory::shutdown();
if (start) Memory::init();
Memory::gFromScript = true;
Memory::gStackTrace = stackTrace;
}
#else #else
// Don't manage our own memory // Don't manage our own memory

View file

@ -54,7 +54,9 @@
#cmakedefine TORQUE_MULTITHREAD #cmakedefine TORQUE_MULTITHREAD
/// Define me if you want to disable Torque memory manager. /// Define me if you want to disable Torque memory manager.
#ifndef TORQUE_ENABLE_ASSERTS
#cmakedefine TORQUE_DISABLE_MEMORY_MANAGER #cmakedefine TORQUE_DISABLE_MEMORY_MANAGER
#endif
/// Define me if you want to disable the virtual mount system. /// Define me if you want to disable the virtual mount system.
#cmakedefine TORQUE_DISABLE_VIRTUAL_MOUNT_SYSTEM #cmakedefine TORQUE_DISABLE_VIRTUAL_MOUNT_SYSTEM