Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

277 lines
6.3 KiB

/*++
Copyright (C) 1998-1999 Microsoft Corporation
Module Name:
NEWNEW.CPP
Abstract:
CReuseMemoryManager
History:
--*/
#include "precomp.h"
#include <wbemcomn.h>
#include <sync.h>
#include "newnew.h"
const int constMinAllocationSize = 4096;
const int constMaxAllocationSize = 1024 * 1024;
const double constNextAllocationFactor = 2.0;
void CTempMemoryManager::CAllocation::Init(size_t dwAllocationSize)
{
m_dwAllocationSize = dwAllocationSize;
m_dwUsed = 0;
m_dwFirstFree = GetHeaderSize();
}
void* CTempMemoryManager::CAllocation::Alloc(size_t nBlockSize)
{
if(m_dwFirstFree + nBlockSize <= m_dwAllocationSize)
{
m_dwUsed += nBlockSize;
void* p = ((byte*)this) + m_dwFirstFree;
m_dwFirstFree += nBlockSize;
return p;
}
else
return NULL;
}
bool CTempMemoryManager::CAllocation::Contains(void* p)
{
return (p > this && p <= GetEnd());
}
void CTempMemoryManager::CAllocation::Destroy()
{
VirtualFree(this, 0, MEM_RELEASE);
}
bool CTempMemoryManager::CAllocation::Free(size_t nBlockSize)
{
m_dwUsed -= nBlockSize;
if(m_dwUsed== 0)
{
m_dwFirstFree = GetHeaderSize();
return true;
}
else
return false;
}
void* CTempMemoryManager::Allocate(size_t nBlockSize)
{
//
// Add the space for the length of the block
//
nBlockSize += DEF_ALIGNED(sizeof(DWORD));
nBlockSize = RoundUp(nBlockSize);
CInCritSec ics(&m_cs);
//
// Check if the last allocation has room
//
int nAllocations = m_pAllocations->GetSize();
CAllocation* pLast = NULL;
if(nAllocations)
{
pLast = (*m_pAllocations)[nAllocations-1];
void* p = pLast->Alloc(nBlockSize);
if(p)
{
*(DWORD*)p = nBlockSize;
m_dwTotalUsed += nBlockSize;
m_dwNumAllocations++;
return ((BYTE*)p) + DEF_ALIGNED(sizeof(DWORD));
}
else if(pLast->GetUsedSize() == 0)
{
//
// The last allocation record is actually empty --- we don't want
// to leave it there, as it will just dangle
//
m_dwTotalAllocated -= pLast->GetAllocationSize();
pLast->Destroy();
(*m_pAllocations).RemoveAt(nAllocations-1);
}
}
//
// No room: need a new allocation. The size shall be double the previous
// size, or 1M if too large
//
size_t dwAllocationSize = 0;
if(nAllocations == 0)
{
//
// First time: constant size
//
dwAllocationSize = constMinAllocationSize;
}
else
{
//
// Not first time: allocation constant factor of the total, but not
// larger that a constant.
//
dwAllocationSize = m_dwTotalUsed * constNextAllocationFactor;
if(dwAllocationSize > constMaxAllocationSize)
dwAllocationSize = constMaxAllocationSize;
if(dwAllocationSize < constMinAllocationSize)
dwAllocationSize = constMinAllocationSize;
}
if(dwAllocationSize < CAllocation::GetMinAllocationSize(nBlockSize))
{
dwAllocationSize = CAllocation::GetMinAllocationSize(nBlockSize);
}
//
// VirtualAlloc it and read back the actual size of the allocation
//
CAllocation* pAlloc = (CAllocation*)
VirtualAlloc(NULL, dwAllocationSize, MEM_COMMIT, PAGE_READWRITE);
if(pAlloc == NULL)
return NULL;
MEMORY_BASIC_INFORMATION info;
VirtualQuery(pAlloc, &info, sizeof(MEMORY_BASIC_INFORMATION));
//
// Initialize it, and add it to the list of allocations
//
pAlloc->Init(info.RegionSize);
m_pAllocations->Add(pAlloc);
m_dwTotalAllocated += dwAllocationSize;
m_dwNumAllocations++;
m_dwNumMisses++;
//
// Allocation memory from it
//
void* p = pAlloc->Alloc(nBlockSize);
if(p)
{
*(DWORD*)p = nBlockSize;
m_dwTotalUsed += nBlockSize;
return ((BYTE*)p) + DEF_ALIGNED(sizeof(DWORD));
}
else
return NULL;
}
void CTempMemoryManager::Free(void* p, size_t nBlockSize)
{
if (p == NULL)
return;
CInCritSec ics(&m_cs);
//
// Figure out the size of the allocation
//
nBlockSize = *(DWORD*)((BYTE*)p - DEF_ALIGNED(sizeof(DWORD)));
//
// Search for it in the allocations
//
for(int i = 0; i < m_pAllocations->GetSize(); i++)
{
CAllocation* pAlloc = (*m_pAllocations)[i];
if(pAlloc->Contains(p))
{
//
// Found it. Remove and deallocate block if last. Except that we
// do not want to deallocate the last minimal block --- otherwise
// small allocations will just keep VirtualAllocing all the time
//
m_dwTotalUsed -= nBlockSize;
bool bLastInAlloc = pAlloc->Free(nBlockSize);
if(!bLastInAlloc)
return;
bool bDestroy = false;
if(m_pAllocations->GetSize() != i+1)
{
//
// This is not the last record. Destroy it
//
bDestroy = true;
}
else
{
//
// This is the last record. Do more tests
//
if(m_pAllocations->GetSize() > 1)
bDestroy = true;
else if((*m_pAllocations)[0]->GetAllocationSize() !=
constMinAllocationSize)
bDestroy = true;
}
if(bDestroy)
{
m_dwTotalAllocated -= pAlloc->GetAllocationSize();
pAlloc->Destroy();
(*m_pAllocations).RemoveAt(i);
}
return;
}
}
//
// Bad news: freeing something we don't own!
//
return;
}
void CTempMemoryManager::Clear()
{
for(int i = 0; i < m_pAllocations->GetSize(); i++)
{
CAllocation* pAlloc = (*m_pAllocations)[i];
pAlloc->Destroy();
}
m_pAllocations->RemoveAll();
}
CTempMemoryManager::CTempMemoryManager() :
m_dwTotalUsed(0), m_dwTotalAllocated(0), m_dwNumAllocations(0),
m_dwNumMisses(0), m_pAllocations(NULL)
{
m_pAllocations = new CPointerArray<CAllocation>;
}
CTempMemoryManager::~CTempMemoryManager()
{
Clear();
delete m_pAllocations;
}