source-engine/engine/zone.cpp

170 lines
4.1 KiB
C++
Raw Normal View History

2020-04-23 00:56:21 +08:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// ZONE MEMORY ALLOCATION
//
// There is never any space between memblocks, and there will never be two
// contiguous free memblocks.
//
// The rover can be left pointing at a non-empty block
//
// The zone calls are pretty much only used for small strings and structures,
// all big things are allocated on the hunk.
//=============================================================================//
#include "basetypes.h"
#include "zone.h"
#include "host.h"
#include "tier1/strtools.h"
#include "tier0/icommandline.h"
#include "memstack.h"
#include "datacache/idatacache.h"
#include "sys_dll.h"
#include "tier0/memalloc.h"
#define MINIMUM_WIN_MEMORY 0x03000000 // FIXME: copy from sys_dll.cpp, find a common header at some point
#ifdef _X360
#define HUNK_USE_16MB_PAGE
#endif
CMemoryStack g_HunkMemoryStack;
#ifdef HUNK_USE_16MB_PAGE
CMemoryStack g_HunkOverflow;
static bool g_bWarnedOverflow;
#endif
static int GetTargetCacheSize()
{
int nMemLimit = host_parms.memsize - Hunk_Size();
if ( nMemLimit < 0x100000 )
{
nMemLimit = 0x100000;
}
return nMemLimit;
}
/*
===================
Hunk_AllocName
===================
*/
void *Hunk_AllocName (int size, const char *name, bool bClear)
{
MEM_ALLOC_CREDIT();
void * p = g_HunkMemoryStack.Alloc( size, bClear );
if ( p )
return p;
#ifdef HUNK_USE_16MB_PAGE
if ( !g_bWarnedOverflow )
{
g_bWarnedOverflow = true;
DevMsg( "Note: Hunk base page exhausted\n" );
}
p = g_HunkOverflow.Alloc( size, bClear );
if ( p )
return p;
#endif
Error( "Engine hunk overflow!\n" );
return NULL;
}
/*
===================
Hunk_Alloc
===================
*/
void *Hunk_Alloc(int size, bool bClear )
{
MEM_ALLOC_CREDIT();
return Hunk_AllocName( size, NULL, bClear );
}
int Hunk_LowMark(void)
{
return (int)( g_HunkMemoryStack.GetCurrentAllocPoint() );
}
void Hunk_FreeToLowMark(int mark)
{
Assert( mark < g_HunkMemoryStack.GetSize() );
#ifdef HUNK_USE_16MB_PAGE
g_HunkOverflow.FreeAll();
g_bWarnedOverflow = false;
#endif
g_HunkMemoryStack.FreeToAllocPoint( mark );
}
int Hunk_MallocSize()
{
#ifdef HUNK_USE_16MB_PAGE
return g_HunkMemoryStack.GetSize() + g_HunkOverflow.GetSize();
#else
return g_HunkMemoryStack.GetSize();
#endif
}
int Hunk_Size()
{
#ifdef HUNK_USE_16MB_PAGE
return g_HunkMemoryStack.GetUsed() + g_HunkOverflow.GetUsed();
#else
return g_HunkMemoryStack.GetUsed();
#endif
}
void Hunk_Print()
{
#ifdef HUNK_USE_16MB_PAGE
Msg( "Total used memory: %d (%d/%d)\n", Hunk_Size(), g_HunkMemoryStack.GetUsed(), g_HunkOverflow.GetUsed() );
Msg( "Total committed memory: %d (%d/%d)\n", Hunk_MallocSize(), g_HunkMemoryStack.GetSize(), g_HunkOverflow.GetSize() );
#else
Msg( "Total used memory: %d\n", Hunk_Size() );
Msg( "Total committed memory: %d\n", Hunk_MallocSize() );
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void Memory_Init( void )
{
MEM_ALLOC_CREDIT();
int nMaxBytes = 48*1024*1024;
const int nMinCommitBytes = 0x8000;
#ifndef HUNK_USE_16MB_PAGE
const int nInitialCommit = 0x280000;
while ( !g_HunkMemoryStack.Init( nMaxBytes, nMinCommitBytes, nInitialCommit ) )
{
Warning( "Unable to allocate %d MB of memory, trying %d MB instead\n", nMaxBytes, nMaxBytes/2 );
nMaxBytes /= 2;
if ( nMaxBytes < MINIMUM_WIN_MEMORY )
{
Error( "Failed to allocate minimum memory requirement for game (%d MB)\n", MINIMUM_WIN_MEMORY/(1024*1024));
}
}
#else
if ( !g_HunkMemoryStack.InitPhysical( 16*1024*1024 ) || !g_HunkOverflow.Init( nMaxBytes - 16*1024*1024, nMinCommitBytes ) )
{
Error( "Failed to allocate minimum memory requirement for game (%d MB)\n", nMaxBytes );
}
#endif
g_pDataCache->SetSize( GetTargetCacheSize() );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void Memory_Shutdown( void )
{
g_HunkMemoryStack.FreeAll();
// This disconnects the engine data cache
g_pDataCache->SetSize( 0 );
}