MF_API MFString MFString_GetStats() { size_t overhead = stringPool.GetTotalMemory() + stringPool.GetOverheadMemory() + stringHeap.GetOverheadMemory(); size_t waste = 0, averageSize = 0; // calculate waste int numStrings = stringPool.GetNumAllocated(); for(int a=0; a<numStrings; ++a) { MFStringData *pString = (MFStringData*)stringPool.GetItem(a); size_t allocated = pString->allocated; if(allocated) { size_t bytes = pString->bytes+1; averageSize += bytes; waste += allocated - bytes; } } if(numStrings) averageSize /= numStrings; MFString desc; desc.Reserve(1024); desc = MFStr("String heap memory: " MFFMT_SIZE_T " allocated/" MFFMT_SIZE_T " reserved + " MFFMT_SIZE_T " overhead Waste: " MFFMT_SIZE_T " Average length: " MFFMT_SIZE_T "\n\tPool: %d/%d", stringHeap.GetAllocatedMemory(), stringHeap.GetTotalMemory(), overhead, waste, averageSize, stringPool.GetNumAllocated(), stringPool.GetNumReserved()); int numGroups = stringHeap.GetNumPools(); for(int a=0; a<numGroups; ++a) { MFObjectPool *pPool = stringHeap.GetPool(a); desc += MFStr("\n\t\t" MFFMT_SIZE_T " byte: %d/%d", pPool->GetObjectSize(), pPool->GetNumAllocated(), pPool->GetNumReserved()); } return desc; }
MF_API void MFString_Dump() { MFString temp = MFString_GetStats(); MFDebug_Log(1, "\n-------------------------------------------------------------------------------------------------------"); MFDebug_Log(1, temp.CStr()); // dump all strings... MFDebug_Log(1, ""); int numStrings = stringPool.GetNumAllocated(); for(int a=0; a<numStrings; ++a) { MFStringData *pString = (MFStringData*)stringPool.GetItem(a); MFDebug_Log(1, MFStr("%d refs, " MFFMT_SIZE_T "b: \"%s\"", pString->refCount, pString->allocated, pString->pMemory)); } }
MF_API bool MFHeap_ValidateHeap() { #if defined(_USE_ALLOC_TRACKER) MFThread_LockMutex(gAllocMutex); if(gPoolInitialised) { int numAllocated = gAllocList.GetNumAllocated(); for(int a=0; a<numAllocated; ++a) { void *pMem = *(void**)gAllocList.GetItem(a); if(!MFHeap_ValidateMemory(pMem)) { MFDebug_Assert(false, "Corrupt memory allocation!"); return false; } } } MFThread_ReleaseMutex(gAllocMutex); #endif return true; }
MF_API void MFHeap_Free(void *pMem) { MFCALLSTACK; if(!pMem) { MFDebug_Warn(3, "Attemptd to Free 'NULL' pointer."); return; } MFAllocHeader *pHeader = &((MFAllocHeader*)pMem)[-1]; MFDebug_Assert(MFHeap_ValidateMemory(pMem), MFStr("Memory corruption detected!!\n%s(%d)", pHeader->pFile, pHeader->line)); MFThread_LockMutex(gAllocMutex); MFHeap *pHeap = pHeader->pHeap; if(pHeap->heapType != MFHT_Debug) { #if defined(_USE_TRACKING_HASH_TABLE) int hash = MFUtil_HashPointer(pMem) % MFHeap_AllocTableLength; MFHeap_AllocItem *pT = gpAllocTable[hash]; if(pT) { if(pT->pMemory == pMem) { gpAllocTable[hash] = pT->pNext; gAllocHeaderPool.Free(pT); } else { while(pT->pNext && pT->pNext->pMemory != pMem) pT = pT->pNext; if(pT->pNext) { MFHeap_AllocItem *pTN = pT->pNext; pT->pNext = pTN->pNext; gAllocHeaderPool.Free(pTN); } } } #endif #if defined(_USE_ALLOC_TRACKER) if(gPoolInitialised) { int numAllocs = gAllocList.GetNumAllocated(); for(int a=0; a<numAllocs; ++a) { void **ppAlloc = (void**)gAllocList.GetItem(a); if(*ppAlloc == pMem) { gAllocList.Free(ppAlloc); break; } } } #endif } #if !defined(_RETAIL) int pad = 0; while(pad < (int)sizeof(MFAllocHeader)) pad += heapAlignment; size_t extra = pad + sizeof(MFAllocHeader) + MFHeap_MungwallBytes; pHeap->totalAllocated -= pHeader->size + extra; pHeap->totalWaste -= extra; --pHeap->allocCount; // MFDebug_Log(2, MFStr("Free: %08X, %d bytes - %s:(%d)", pMem, pHeader->size, pHeader->pFile, (int)pHeader->line)); #endif MFHeap *pAllocHeap = pHeader->pHeap; MFCopyMemory((char*)pMem + pHeader->size, "freefreefreefree", MFHeap_MungwallBytes); MFCopyMemory((char*)pMem - 8, "freefreefreefree", MFHeap_MungwallBytes); MFMemSet(pMem, 0xFE, pHeader->size); pAllocHeap->pCallbacks->pFree((char*)pMem - pHeader->alignment, pAllocHeap->pHeapData); MFThread_ReleaseMutex(gAllocMutex); }