vphysics: fix saverestore

This commit is contained in:
nillerusr
2022-06-14 13:09:10 +03:00
parent b84ad64171
commit 94916a20ce
10 changed files with 300 additions and 122 deletions
+1 -1
View File
@@ -110,7 +110,7 @@ DECLARE_FIELD_SIZE( FIELD_MODELNAME, sizeof(void*))
DECLARE_FIELD_SIZE( FIELD_SOUNDNAME, sizeof(void*))
DECLARE_FIELD_SIZE( FIELD_EHANDLE, sizeof(void*))
DECLARE_FIELD_SIZE( FIELD_CLASSPTR, sizeof(void*))
DECLARE_FIELD_SIZE( FIELD_EDICT, sizeof(int))
DECLARE_FIELD_SIZE( FIELD_EDICT, sizeof(void*))
DECLARE_FIELD_SIZE( FIELD_POSITION_VECTOR, 3 * sizeof(float))
DECLARE_FIELD_SIZE( FIELD_TIME, sizeof(float))
DECLARE_FIELD_SIZE( FIELD_TICK, sizeof(int))
+10
View File
@@ -525,6 +525,16 @@ typedef void * HINSTANCE;
#error
#endif
// !!! NOTE: if you get a compile error here, you are using VALIGNOF on an abstract type :NOTE !!!
#define VALIGNOF_PORTABLE( type ) ( sizeof( AlignOf_t<type> ) - sizeof( type ) )
#if defined( COMPILER_GCC ) || defined( COMPILER_MSVC )
#define VALIGNOF( type ) __alignof( type )
#define VALIGNOF_TEMPLATE_SAFE( type ) VALIGNOF_PORTABLE( type )
#else
#error "PORT: Code only tested with MSVC! Must validate with new compiler, and use built-in keyword if available."
#endif
// Pull in the /analyze code annotations.
#include "annotations.h"
+24 -5
View File
@@ -1,4 +1,4 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
@@ -65,6 +65,8 @@ public:
// -----------------------------------------------------------------------------
void SetFreeOnDestruct( bool value ) { m_freeOnDestruct = value; }
// Debugging only!!!!
void GetLRUHandleList( CUtlVector< memhandle_t >& list );
void GetLockHandleList( CUtlVector< memhandle_t >& list );
@@ -77,6 +79,7 @@ protected:
void *GetResource_NoLock( memhandle_t handle );
void *GetResource_NoLockNoLRUTouch( memhandle_t handle );
void *LockResource( memhandle_t handle );
void *LockResourceReturnCount( int *pCount, memhandle_t handle );
// NOTE: you must call this from the destructor of the derived class! (will assert otherwise)
void FreeAllLists() { FlushAll(); m_listsAreFreed = true; }
@@ -123,7 +126,8 @@ protected:
unsigned short m_lockList;
unsigned short m_freeList;
unsigned short m_listsAreFreed : 1;
unsigned short m_unused : 15;
unsigned short m_freeOnDestruct : 1;
unsigned short m_unused : 14;
};
@@ -139,7 +143,10 @@ public:
~CDataManager<STORAGE_TYPE, CREATE_PARAMS, LOCK_TYPE, MUTEX_TYPE>()
{
// NOTE: This must be called in all implementations of CDataManager
FreeAllLists();
if ( m_freeOnDestruct )
{
FreeAllLists();
}
}
// Use GetData() to translate pointer to LOCK_TYPE
@@ -154,6 +161,17 @@ public:
return NULL;
}
LOCK_TYPE LockResourceReturnCount( int *pCount, memhandle_t hMem )
{
void *pLock = BaseClass::LockResourceReturnCount( pCount, hMem );
if ( pLock )
{
return StoragePointer(pLock)->GetData();
}
return NULL;
}
// Use GetData() to translate pointer to LOCK_TYPE
LOCK_TYPE GetResource_NoLock( memhandle_t hMem )
{
@@ -181,8 +199,9 @@ public:
memhandle_t CreateResource( const CREATE_PARAMS &createParams, bool bCreateLocked = false )
{
BaseClass::EnsureCapacity(STORAGE_TYPE::EstimatedSize(createParams));
unsigned short memoryIndex = BaseClass::CreateHandle( bCreateLocked );
STORAGE_TYPE *pStore = STORAGE_TYPE::CreateResource( createParams );
AUTO_LOCK_( CDataManagerBase, *this );
unsigned short memoryIndex = BaseClass::CreateHandle( bCreateLocked );
return BaseClass::StoreResourceInHandle( memoryIndex, pStore, pStore->Size() );
}
@@ -251,7 +270,7 @@ private:
inline unsigned short CDataManagerBase::FromHandle( memhandle_t handle )
{
uintp fullWord = (uintp)handle;
unsigned int fullWord = (unsigned int)reinterpret_cast<uintp>( handle );
unsigned short serial = fullWord>>16;
unsigned short index = fullWord & 0xFFFF;
index--;
+163 -69
View File
@@ -1,4 +1,4 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
@@ -30,27 +30,19 @@
typedef void (*MemoryPoolReportFunc_t)( PRINTF_FORMAT_STRING char const* pMsg, ... );
// Ways a memory pool can grow when it needs to make a new blob:
enum MemoryPoolGrowType_t
{
UTLMEMORYPOOL_GROW_NONE=0, // Don't allow new blobs.
UTLMEMORYPOOL_GROW_FAST=1, // New blob size is numElements * (i+1) (ie: the blocks it allocates
// get larger and larger each time it allocates one).
UTLMEMORYPOOL_GROW_SLOW=2 // New blob size is numElements.
};
class CUtlMemoryPool
{
public:
// !KLUDGE! For legacy code support, import the global enum into this scope
// Ways the memory pool can grow when it needs to make a new blob.
enum MemoryPoolGrowType_t
{
GROW_NONE=UTLMEMORYPOOL_GROW_NONE,
GROW_FAST=UTLMEMORYPOOL_GROW_FAST,
GROW_SLOW=UTLMEMORYPOOL_GROW_SLOW
GROW_NONE=0, // Don't allow new blobs.
GROW_FAST=1, // New blob size is numElements * (i+1) (ie: the blocks it allocates
// get larger and larger each time it allocates one).
GROW_SLOW=2 // New blob size is numElements.
};
CUtlMemoryPool( int blockSize, int numElements, int growMode = UTLMEMORYPOOL_GROW_FAST, const char *pszAllocOwner = NULL, int nAlignment = 0 );
CUtlMemoryPool( int blockSize, int numElements, int growMode = GROW_FAST, const char *pszAllocOwner = NULL, int nAlignment = 0 );
~CUtlMemoryPool();
void* Alloc(); // Allocate the element size you specified in the constructor.
@@ -66,8 +58,12 @@ public:
static void SetErrorReportFunc( MemoryPoolReportFunc_t func );
// returns number of allocated blocks
int Count() { return m_BlocksAllocated; }
int PeakCount() { return m_PeakAlloc; }
int Count() const { return m_BlocksAllocated; }
int PeakCount() const { return m_PeakAlloc; }
int BlockSize() const { return m_BlockSize; }
int Size() const;
bool IsAllocationWithinPool( void *pMem ) const;
protected:
class CBlob
@@ -89,14 +85,13 @@ protected:
int m_GrowMode; // GROW_ enum.
// Put m_BlocksAllocated in front of m_pHeadOfFreeList for better
// packing on 64-bit where pointers are 8-byte aligned.
int m_BlocksAllocated;
// FIXME: Change m_ppMemBlob into a growable array?
void *m_pHeadOfFreeList;
int m_PeakAlloc;
unsigned short m_nAlignment;
unsigned short m_NumBlobs;
// Group up pointers at the end of the class to avoid padding bloat
// FIXME: Change m_ppMemBlob into a growable array?
void *m_pHeadOfFreeList;
const char * m_pszAllocOwner;
// CBlob could be not a multiple of 4 bytes so stuff it at the end here to keep us otherwise aligned
CBlob m_BlobHead;
@@ -106,13 +101,12 @@ protected:
//-----------------------------------------------------------------------------
//
// Multi-thread/Thread Safe Memory Class
//-----------------------------------------------------------------------------
class CMemoryPoolMT : public CUtlMemoryPool
{
public:
// MoeMod : add alignment
CMemoryPoolMT(int blockSize, int numElements, int growMode = UTLMEMORYPOOL_GROW_FAST, const char *pszAllocOwner = NULL, int nAlignment = 0) : CUtlMemoryPool( blockSize, numElements, growMode, pszAllocOwner, nAlignment) {}
CMemoryPoolMT( int blockSize, int numElements, int growMode = GROW_FAST, const char *pszAllocOwner = NULL, int nAlignment = 0) : CUtlMemoryPool( blockSize, numElements, growMode, pszAllocOwner, nAlignment ) {}
void* Alloc() { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::Alloc(); }
@@ -136,15 +130,8 @@ template< class T >
class CClassMemoryPool : public CUtlMemoryPool
{
public:
// MoeMod : bad default align here, should be alignof(T)
CClassMemoryPool(int numElements, int growMode = GROW_FAST, int nAlignment = alignof(T) ) :
CUtlMemoryPool( sizeof(T), numElements, growMode, MEM_ALLOC_CLASSNAME(T), nAlignment ) {
#ifdef PLATFORM_64BITS
COMPILE_TIME_ASSERT( sizeof(CUtlMemoryPool) == 64 );
#else
COMPILE_TIME_ASSERT( sizeof(CUtlMemoryPool) == 48 );
#endif
}
CClassMemoryPool(int numElements, int growMode = GROW_FAST, int nAlignment = 0 ) :
CUtlMemoryPool( sizeof(T), numElements, growMode, MEM_ALLOC_CLASSNAME(T), nAlignment ) {}
T* Alloc();
T* AllocZero();
@@ -153,16 +140,15 @@ public:
void Clear();
};
//-----------------------------------------------------------------------------
// Specialized pool for aligned data management (e.g., Xbox cubemaps)
// Specialized pool for aligned data management (e.g., Xbox textures)
//-----------------------------------------------------------------------------
template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, int COMPACT_THRESHOLD = 4 >
template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, bool GROWMODE = false, int COMPACT_THRESHOLD = 4 >
class CAlignedMemPool
{
enum
{
BLOCK_SIZE = ALIGN_VALUE( ITEM_SIZE, ALIGNMENT ) > 8 ? ALIGN_VALUE( ITEM_SIZE, ALIGNMENT ) : 8
BLOCK_SIZE = COMPILETIME_MAX( ALIGN_VALUE( ITEM_SIZE, ALIGNMENT ), 8 ),
};
public:
@@ -174,13 +160,13 @@ public:
static int __cdecl CompareChunk( void * const *ppLeft, void * const *ppRight );
void Compact();
int NumTotal() { return m_Chunks.Count() * ( CHUNK_SIZE / BLOCK_SIZE ); }
int NumAllocated() { return NumTotal() - m_nFree; }
int NumFree() { return m_nFree; }
int NumTotal() { AUTO_LOCK( m_mutex ); return m_Chunks.Count() * ( CHUNK_SIZE / BLOCK_SIZE ); }
int NumAllocated() { AUTO_LOCK( m_mutex ); return NumTotal() - m_nFree; }
int NumFree() { AUTO_LOCK( m_mutex ); return m_nFree; }
int BytesTotal() { return NumTotal() * BLOCK_SIZE; }
int BytesAllocated() { return NumAllocated() * BLOCK_SIZE; }
int BytesFree() { return NumFree() * BLOCK_SIZE; }
int BytesTotal() { AUTO_LOCK( m_mutex ); return NumTotal() * BLOCK_SIZE; }
int BytesAllocated() { AUTO_LOCK( m_mutex ); return NumAllocated() * BLOCK_SIZE; }
int BytesFree() { AUTO_LOCK( m_mutex ); return NumFree() * BLOCK_SIZE; }
int ItemSize() { return ITEM_SIZE; }
int BlockSize() { return BLOCK_SIZE; }
@@ -197,7 +183,9 @@ private:
FreeBlock_t * m_pFirstFree;
int m_nFree;
CAllocator m_Allocator;
float m_TimeLastCompact;
double m_TimeLastCompact;
CThreadFastMutex m_mutex;
};
//-----------------------------------------------------------------------------
@@ -228,7 +216,7 @@ public:
void Purge()
{
T *p;
T *p = NULL;
while ( m_AvailableObjects.PopItem( &p ) )
{
delete p;
@@ -237,7 +225,7 @@ public:
T *GetObject( bool bCreateNewIfEmpty = bDefCreateNewIfEmpty )
{
T *p;
T *p = NULL;
if ( !m_AvailableObjects.PopItem( &p ) )
{
p = ( bCreateNewIfEmpty ) ? new T : NULL;
@@ -255,6 +243,98 @@ private:
};
//-----------------------------------------------------------------------------
// Fixed budget pool with overflow to malloc
//-----------------------------------------------------------------------------
template <size_t PROVIDED_ITEM_SIZE, int ITEM_COUNT>
class CFixedBudgetMemoryPool
{
public:
CFixedBudgetMemoryPool()
{
m_pBase = m_pLimit = 0;
COMPILE_TIME_ASSERT( ITEM_SIZE % 4 == 0 );
}
bool Owns( void *p )
{
return ( p >= m_pBase && p < m_pLimit );
}
void *Alloc()
{
MEM_ALLOC_CREDIT_CLASS();
#ifndef USE_MEM_DEBUG
if ( !m_pBase )
{
LOCAL_THREAD_LOCK();
if ( !m_pBase )
{
byte *pMemory = m_pBase = (byte *)malloc( ITEM_COUNT * ITEM_SIZE );
m_pLimit = m_pBase + ( ITEM_COUNT * ITEM_SIZE );
for ( int i = 0; i < ITEM_COUNT; i++ )
{
m_freeList.Push( (TSLNodeBase_t *)pMemory );
pMemory += ITEM_SIZE;
}
}
}
void *p = m_freeList.Pop();
if ( p )
return p;
#endif
return malloc( ITEM_SIZE );
}
void Free( void *p )
{
#ifndef USE_MEM_DEBUG
if ( Owns( p ) )
m_freeList.Push( (TSLNodeBase_t *)p );
else
#endif
free( p );
}
void Clear()
{
#ifndef USE_MEM_DEBUG
if ( m_pBase )
{
free( m_pBase );
}
m_pBase = m_pLimit = 0;
Construct( &m_freeList );
#endif
}
bool IsEmpty()
{
#ifndef USE_MEM_DEBUG
if ( m_pBase && m_freeList.Count() != ITEM_COUNT )
return false;
#endif
return true;
}
enum
{
ITEM_SIZE = ALIGN_VALUE( PROVIDED_ITEM_SIZE, TSLIST_NODE_ALIGNMENT )
};
CTSListBase m_freeList;
byte *m_pBase;
byte *m_pLimit;
};
#define BIND_TO_FIXED_BUDGET_POOL( poolName ) \
inline void* operator new( size_t size ) { return poolName.Alloc(); } \
inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { return poolName.Alloc(); } \
inline void operator delete( void* p ) { poolName.Free(p); } \
inline void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine ) { poolName.Free(p); }
//-----------------------------------------------------------------------------
template< class T >
@@ -263,7 +343,7 @@ inline T* CClassMemoryPool<T>::Alloc()
T *pRet;
{
MEM_ALLOC_CREDIT_(MEM_ALLOC_CLASSNAME(T));
MEM_ALLOC_CREDIT_CLASS();
pRet = (T*)CUtlMemoryPool::Alloc();
}
@@ -280,7 +360,7 @@ inline T* CClassMemoryPool<T>::AllocZero()
T *pRet;
{
MEM_ALLOC_CREDIT_(MEM_ALLOC_CLASSNAME(T));
MEM_ALLOC_CREDIT_CLASS();
pRet = (T*)CUtlMemoryPool::AllocZero();
}
@@ -305,7 +385,7 @@ inline void CClassMemoryPool<T>::Free(T *pMem)
template< class T >
inline void CClassMemoryPool<T>::Clear()
{
CUtlRBTree<void *> freeBlocks;
CUtlRBTree<void *, int> freeBlocks;
SetDefLessFunc( freeBlocks );
void *pCurFree = m_pHeadOfFreeList;
@@ -317,9 +397,9 @@ inline void CClassMemoryPool<T>::Clear()
for( CBlob *pCur=m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur=pCur->m_pNext )
{
// MoeMod : should realign to real data.
T *p = (T *)AlignValue( pCur->m_Data, m_nAlignment );
T *pLimit = (T *)(pCur->m_Data + pCur->m_NumBytes);
int nElements = pCur->m_NumBytes / this->m_BlockSize;
T *p = ( T * ) AlignValue( pCur->m_Data, this->m_nAlignment );
T *pLimit = p + nElements;
while ( p < pLimit )
{
if ( freeBlocks.Find( p ) == freeBlocks.InvalidIndex() )
@@ -334,6 +414,9 @@ inline void CClassMemoryPool<T>::Clear()
}
//-----------------------------------------------------------------------------
// Macros that make it simple to make a class use a fixed-size allocator
// Put DECLARE_FIXEDSIZE_ALLOCATOR in the private section of a class,
@@ -364,7 +447,7 @@ inline void CClassMemoryPool<T>::Clear()
static CMemoryPoolMT s_Allocator
#define DEFINE_FIXEDSIZE_ALLOCATOR_MT( _class, _initsize, _grow ) \
CMemoryPoolMT _class::s_Allocator(sizeof(_class), _initsize, _grow, #_class " pool", alignof(_class))
CMemoryPoolMT _class::s_Allocator(sizeof(_class), _initsize, _grow, #_class " pool")
//-----------------------------------------------------------------------------
// Macros that make it simple to make a class use a fixed-size allocator
@@ -385,21 +468,30 @@ inline void CClassMemoryPool<T>::Clear()
CUtlMemoryPool* _class::s_pAllocator = _allocator
template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, int COMPACT_THRESHOLD >
inline CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, COMPACT_THRESHOLD>::CAlignedMemPool()
template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, bool GROWMODE, int COMPACT_THRESHOLD >
inline CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, GROWMODE, COMPACT_THRESHOLD>::CAlignedMemPool()
: m_pFirstFree( 0 ),
m_nFree( 0 ),
m_TimeLastCompact( 0 )
{
COMPILE_TIME_ASSERT( sizeof( FreeBlock_t ) >= BLOCK_SIZE );
COMPILE_TIME_ASSERT( ALIGN_VALUE( sizeof( FreeBlock_t ), ALIGNMENT ) == sizeof( FreeBlock_t ) );
// These COMPILE_TIME_ASSERT checks need to be in individual scopes to avoid build breaks
// on MacOS and Linux due to a gcc bug.
{ COMPILE_TIME_ASSERT( sizeof( FreeBlock_t ) >= BLOCK_SIZE ); }
{ COMPILE_TIME_ASSERT( ALIGN_VALUE( sizeof( FreeBlock_t ), ALIGNMENT ) == sizeof( FreeBlock_t ) ); }
}
template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, int COMPACT_THRESHOLD >
inline void *CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, COMPACT_THRESHOLD>::Alloc()
template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, bool GROWMODE, int COMPACT_THRESHOLD >
inline void *CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, GROWMODE, COMPACT_THRESHOLD>::Alloc()
{
AUTO_LOCK( m_mutex );
if ( !m_pFirstFree )
{
if ( !GROWMODE && m_Chunks.Count() )
{
return NULL;
}
FreeBlock_t *pNew = (FreeBlock_t *)m_Allocator.Alloc( CHUNK_SIZE );
Assert( (unsigned)pNew % ALIGNMENT == 0 );
m_Chunks.AddToTail( pNew );
@@ -420,9 +512,11 @@ inline void *CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, COMPA
return p;
}
template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, int COMPACT_THRESHOLD >
inline void CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, COMPACT_THRESHOLD>::Free( void *p )
template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, bool GROWMODE, int COMPACT_THRESHOLD >
inline void CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, GROWMODE, COMPACT_THRESHOLD>::Free( void *p )
{
AUTO_LOCK( m_mutex );
// Insertion sort to encourage allocation clusters in chunks
FreeBlock_t *pFree = ((FreeBlock_t *)p);
FreeBlock_t *pCur = m_pFirstFree;
@@ -448,9 +542,9 @@ inline void CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, COMPAC
if ( m_nFree >= ( CHUNK_SIZE / BLOCK_SIZE ) * COMPACT_THRESHOLD )
{
float time = Plat_FloatTime();
float compactTime = ( m_nFree >= ( CHUNK_SIZE / BLOCK_SIZE ) * COMPACT_THRESHOLD * 4 ) ? 15.0 : 30.0;
if ( m_TimeLastCompact > time || m_TimeLastCompact + compactTime < Plat_FloatTime() )
double time = Plat_FloatTime();
double compactTime = ( m_nFree >= ( CHUNK_SIZE / BLOCK_SIZE ) * COMPACT_THRESHOLD * 4 ) ? 15.0 : 30.0;
if ( m_TimeLastCompact > time || m_TimeLastCompact + compactTime < time )
{
Compact();
m_TimeLastCompact = time;
@@ -458,14 +552,14 @@ inline void CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, COMPAC
}
}
template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, int COMPACT_THRESHOLD >
inline int __cdecl CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, COMPACT_THRESHOLD>::CompareChunk( void * const *ppLeft, void * const *ppRight )
template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, bool GROWMODE, int COMPACT_THRESHOLD >
inline int __cdecl CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, GROWMODE, COMPACT_THRESHOLD>::CompareChunk( void * const *ppLeft, void * const *ppRight )
{
return (int)(((uintp)*ppLeft) - ((uintp)*ppRight));
return static_cast<int>( (intp)*ppLeft - (intp)*ppRight );
}
template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, int COMPACT_THRESHOLD >
inline void CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, COMPACT_THRESHOLD>::Compact()
template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, bool GROWMODE, int COMPACT_THRESHOLD >
inline void CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, GROWMODE, COMPACT_THRESHOLD>::Compact()
{
FreeBlock_t *pCur = m_pFirstFree;
FreeBlock_t *pPrev = NULL;