Files
Client/Engine/Effect/MemoryPool.cpp
LGram16 e067522598 Initial commit: ROW Client source code
Game client codebase including:
- CharacterActionControl: Character and creature management
- GlobalScript: Network, items, skills, quests, utilities
- RYLClient: Main client application with GUI and event handlers
- Engine: 3D rendering engine (RYLGL)
- MemoryManager: Custom memory allocation
- Library: Third-party dependencies (DirectX, boost, etc.)
- Tools: Development utilities

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 16:24:34 +09:00

330 lines
7.3 KiB
C++

#include "MemoryPool.h"
#include <winsock2.h>
#include <windows.h>
#include <new>
#include <iostream>
#include <fstream>
#include "GMMemory.h"
const char* const CFixedPool::ms_strErrLogFileName = "FixedMemoryPool_ErrLog.txt";
struct CFixedPool::ChunkNode
{
ChunkNode* m_pNext;
};
struct CFixedPool::AllocateInfo
{
AllocateInfo* m_pNext;
static const int ms_nPaddingSize;
static const char* ms_strAllocatedPadding;
static const char* ms_strDeallocatedPadding;
static const char* ms_strNotUsedPadding;
};
const char* CFixedPool::AllocateInfo::ms_strAllocatedPadding = "Aloc";
const char* CFixedPool::AllocateInfo::ms_strDeallocatedPadding = "Free";
const char* CFixedPool::AllocateInfo::ms_strNotUsedPadding = "Nuse";
#ifdef MEMPOOL_DBGMODE
const int CFixedPool::AllocateInfo::ms_nPaddingSize = 4;
#else
const int CFixedPool::AllocateInfo::ms_nPaddingSize = 0;
#endif
#include "GMUndefNew.h"
DEFINE_ALLOCATOR(CFixedPool)
{
if(nSize != m_nOriginalSize)
{
return operator new(nSize);
}
m_PoolLock.Lock();
if(NULL == m_pNodeHead)
{
if(!AllocateChunks())
{
return NULL;
}
}
AllocateInfo* pNode = m_pNodeHead;
m_pNodeHead = m_pNodeHead->m_pNext;
++m_nTotalInUse;
m_PoolLock.Unlock();
char* pResult = reinterpret_cast<char*>(pNode);
#ifdef MEMPOOL_DBGMODE
memcpy(pResult + m_nPerAllocateSize - AllocateInfo::ms_nPaddingSize,
AllocateInfo::ms_strAllocatedPadding, AllocateInfo::ms_nPaddingSize);
#endif
return pResult + sizeof(AllocateInfo);
}
DEFINE_DEALLOCATOR(CFixedPool)
{
if(NULL == pDelete)
{
return;
}
if(nSize != m_nOriginalSize)
{
operator delete(pDelete);
return;
}
char* pszDelete = reinterpret_cast<char*>(pDelete) - sizeof(AllocateInfo);
AllocateInfo* pNode = reinterpret_cast<AllocateInfo*>(pszDelete);
#ifdef MEMPOOL_DBGMODE
// 버퍼 오버플로우 혹은 메모리를 여러번 해제.
const char* pszPadding = pszDelete + m_nPerAllocateSize - AllocateInfo::ms_nPaddingSize;
if(0 != memcmp(pszPadding, AllocateInfo::ms_strAllocatedPadding, AllocateInfo::ms_nPaddingSize))
{
LogBufferOverflow(pszPadding);
}
#endif
m_PoolLock.Lock();
pNode->m_pNext = m_pNodeHead;
m_pNodeHead = pNode;
--m_nTotalInUse;
m_PoolLock.Unlock();
}
#include "GMRedefNew.h"
bool CFixedPool::AllocateChunks()
{
#include "GMUndefNew.h"
// Allocation and make list
ChunkNode* pChunkNode = reinterpret_cast<ChunkNode*>(
::operator new(sizeof(ChunkNode) + m_nPerAllocateSize * m_nPerAllocateNum));
#include "GMRedefNew.h"
if(0 == pChunkNode)
{
// Chunk 메모리 할당 에러.
return false;
}
pChunkNode->m_pNext = m_pChunkHead;
m_pChunkHead = pChunkNode;
m_pNodeHead = reinterpret_cast<AllocateInfo*>(m_pChunkHead + 1);
m_nTotalAllocated += m_nPerAllocateNum; // 전체 개수 증가.
char* pMakeList = reinterpret_cast<char*>(m_pNodeHead);
size_t nAllocated = m_nPerAllocateNum - 1;
while(0 < nAllocated--)
{
reinterpret_cast<AllocateInfo*>(pMakeList)->m_pNext =
reinterpret_cast<AllocateInfo*>(pMakeList + m_nPerAllocateSize);
pMakeList += m_nPerAllocateSize;
#ifdef MEMPOOL_DBGMODE
// 메모리가 사용되지 않았음을 나타내는 패딩을 넣음.
memcpy(pMakeList - AllocateInfo::ms_nPaddingSize,
AllocateInfo::ms_strNotUsedPadding, AllocateInfo::ms_nPaddingSize);
#endif
}
reinterpret_cast<AllocateInfo*>(pMakeList)->m_pNext = 0;
return true;
}
CFixedPool::CFixedPool()
: m_pChunkHead(NULL), m_pNodeHead(NULL),
m_nOriginalSize(0), m_nPerAllocateNum(0), m_nPerAllocateSize(0),
m_nTotalAllocated(0), m_nTotalInUse(0)
{
}
CFixedPool::CFixedPool(size_t nPerAllocateSize, size_t nPerAllocateNum,
const char* strMaxPoolName, size_t nNameLen)
: m_pChunkHead(NULL), m_pNodeHead(NULL),
m_nOriginalSize(0), m_nPerAllocateNum(0), m_nPerAllocateSize(0),
m_nTotalAllocated(0), m_nTotalInUse(0)
{
Initialize(nPerAllocateSize, nPerAllocateNum, strMaxPoolName, nNameLen);
}
CFixedPool::~CFixedPool()
{
Destroy();
}
bool CFixedPool::Initialize(size_t nPerAllocateSize, size_t nPerAllocateNum,
const char* strMaxPoolName, size_t nNameLen)
{
Destroy();
m_nOriginalSize = nPerAllocateSize;
m_nPerAllocateNum = nPerAllocateNum;
m_nPerAllocateSize = nPerAllocateSize + GetLeastAllocateSize();
const size_t nLastPos = min(nNameLen, MAX_POOL_NAME - 1);
strncpy(m_pszPoolName, strMaxPoolName, nLastPos);
m_pszPoolName[nLastPos] = 0;
return true;
}
void CFixedPool::LogBufferOverflow(const char* lpBuffer)
{
FILE* pLogFile = fopen(ms_strErrLogFileName, "ab");
if(NULL != pLogFile)
{
SYSTEMTIME sysTime;
GetLocalTime(&sysTime);
__try
{
fprintf(pLogFile, "\n[%d-%d-%d %d:%d:%d] %s 메모리 풀에서 버퍼 오버플로우 또는, "
"메모리 해제가 여러 번 있었습니다. PerAllocateSize = %d(0x%08x)\n<",
sysTime.wYear, sysTime.wMonth, sysTime.wDay, sysTime.wHour, sysTime.wMinute, sysTime.wSecond, m_pszPoolName,
m_nPerAllocateSize, m_nPerAllocateSize);
fwrite(lpBuffer, m_nPerAllocateSize * 2, 1, pLogFile);
}
__finally
{
fprintf(pLogFile, ">");
fclose(pLogFile);
}
}
}
void CFixedPool::Destroy()
{
PoolLock::Syncronize sync(m_PoolLock);
if(0 != m_nTotalInUse)
{
// 메모리 관련 로그를 남긴다. (Chunk를 전부 뒤져서 해제가 되지 않은 메모리를 찾아낸다.)
/*FILE* pLogFile = fopen(ms_strErrLogFileName, "ab");
if(NULL != pLogFile)
{
SYSTEMTIME sysTime;
GetLocalTime(&sysTime);
fprintf(pLogFile, "[%d-%d-%d %d:%d:%d] %s 메모리 풀에서 %d개가 해제되지 않았습니다. 로그로 기록합니다.\r\n",
sysTime.wYear, sysTime.wMonth, sysTime.wDay, sysTime.wHour, sysTime.wMinute, sysTime.wSecond,
m_pszPoolName, m_nTotalInUse);
fclose(pLogFile);
}*/
}
for(ChunkNode* pChunkNode = m_pChunkHead; NULL != pChunkNode;)
{
ChunkNode* pDelNode = pChunkNode;
pChunkNode = pChunkNode->m_pNext;
delete pDelNode;
}
m_nTotalAllocated = m_nTotalInUse = 0;
m_pChunkHead = NULL;
m_pNodeHead = NULL;
}
size_t CFixedPool::GetLeastAllocateSize()
{
return sizeof(AllocateInfo) + AllocateInfo::ms_nPaddingSize;
}
const char* CFixedPool::GetErrFileName()
{
return ms_strErrLogFileName;
}
void CFixedPoolTest::DoTest()
{
const char* const strErrLogFileName = CFixedPool::GetErrFileName();
//printf("%s Test Started.\n", __FUNCTION__);
remove(strErrLogFileName);
CFixedPool pool;
const char* pName = "테스트풀";
const int nSize = 10;
const int nPerAllocate = 100;
const int MAX_ALLOC = nPerAllocate * 10;
void* pAlloc[MAX_ALLOC];
pool.Initialize(nSize, nPerAllocate, pName, strlen(pName));
for(int i = 0; i < MAX_ALLOC; ++i)
{
pAlloc[i] = pool.ALLOC(nSize);
}
for(int i = 0; i < MAX_ALLOC; ++i)
{
pool.FREE(pAlloc[i], nSize);
}
pool.Destroy();
FILE* pFile = fopen(strErrLogFileName, "rb");
if(NULL == pFile)
{
printf("\tTest Successed!\n");
}
else
{
fclose(pFile);
#ifdef WIN32
char szPath[MAX_PATH];
char szFileNameWithPath[MAX_PATH];
UINT nResult = GetWindowsDirectory(szPath, MAX_PATH);
if(0 != nResult && nResult <= MAX_PATH)
{
_snprintf(szFileNameWithPath, MAX_PATH, "%s\\NotePad.exe %s", szPath, strErrLogFileName);
WinExec(szFileNameWithPath, SW_SHOW);
}
#endif
printf("\tMemory Leak or Curruption Detected!\n\tPlease See %s File\n", strErrLogFileName);
}
//printf("%s Test Completed.\n\n");
}