코드설명은 부분적으로 설명하고 전체를 살펴보겠다.
동작 원리나 개념은 앞의 [MemoryPooling_1] 포스트를 참고하면 된다.
header
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #include <vector> class CPoolingManager { typedef char* MEMORYBLOCK; public: static CPoolingManager* Instance(); void CreateObjectList(size_t count, size_t size); // size만큼의 char형 포인터를 count만큼 Object리스트에 add void* ObjectNew(); // pool이 보유한 메모리 리스트가 생성하려는 것보다 적으면 새로 생성 void ReturnToFreeMemory(void* object); // Object을 메모리블럭으로 전환 (alive off) void ReturnToFreeMemoryAll(); // 모든 Bullet을 메모리 블럭으로 전환 (alive off) void DeleteAllMemory(); // 모든 메모리를 해제한다. (게임이 종료되거나 Scene이 변경될때 호출) private: MEMORYBLOCK NewMemoryBlock(size_t size) const; // size만큼의 메모리 블럭을 생성한다. CPoolingManager(); ~CPoolingManager(); // 메모리 블럭을 해제한다. private: std::vector<MEMORYBLOCK> m_ObjectList; int m_ObjectSize; }; | cs |
음.. 뭔가 무지 간단해 보인다.
주석을 달아 놓긴했지만 일단 하나씩 보자.
CPP
가장 먼저
MEMORYBLOCK
이 MemoryPooling클래스는 MEMORYBLOC이라는 타입을 사용한다. 단순하게 char*이고
여기에 원하는 만큼의 메모리를 동적할당해서 블럭형태로 만든다.
바로 NewMemoryBlock(size_t size)함수가 size만큼의 메모리 블럭을 만드는 역할을 한다.
내부는 아래와 같다.
1 2 3 4 5 6 | CPoolingManager::MEMORYBLOCK CPoolingManager::NewMemoryBlock(size_t size) const { MEMORYBLOCK block = new char[size + 1]; // memory alive를 위한 1바이트 추가 생성 memset(block, 0, size + 1); // memory 초기화 및 memory alive = false return block; } | cs |
메모리 블럭을 사용 중인지 알아내기 위해 블럭의 원래 사이즈보다 1크게 할당한다.
또 memset을 이용하여 전체를 초기화한다. 이때 마지막 부분은 false로 되어 사용중이 아니라는 것을 체크한다.
이렇게 만든 메모리블럭들은 CreateObjectList(size_t count, size_t size)함수 안에서 리스트에 등록된다.
CreateObjectList
1 2 3 4 5 6 7 8 9 10 11 | void CPoolingManager::CreateObjectList(size_t count, size_t size) { m_ObjectSize = size; m_ObjectList.reserve(count); while (count--) { MEMORYBLOCK memBlock = NewMemoryBlock(m_ObejctSize); // 하나의 크기가 size만큼의 메모리 블럭을 m_ObejctList.emplace_back(memBlock); // count만큼 생성한다. CObjectManager::Instance()->AddObject(memBlock); } } | cs |
다른 건 신경쓰지말고 중간에 ObjectManager를 보자.
메모리를 어딘가에 등록하고 있다.
클래스 이름처럼 싱글톤으로 구현된 오브젝트 매니저 클래스이다.
ObjectManager에서는 각각의 블럭포인터를 리스트에 가지고 있다가 모든 object의 Execute를 하기 위해 사용한다.
ObjectNew
사실 제일 할말이 많은 부분이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | void* CPoolingManager::ObjectNew() { for (auto object : m_ObejctList) { if (false == object[m_ObjectSize]) { // 메모리가 Free상태면 object[m_ObjectSize] = true; // 메모리를 사용 상태로 전환 후 반환 return object; } } CCLOG("OBJECT LIST OVERFLOWED"); MEMORYBLOCK memBlock = NewMemoryBlock(m_ObjectSize); m_ObejctList.emplace_back(memBlock); CObjectManager::Instance()->AddObject(memBlock); memBlock[m_ObjectSize] = true; // 메모리를 사용 중 상태로 전환 return memBlock; } | cs |
이 함수는 object가 생성될 때, 다시 말해 new 할때 object의 operator new에서 호출한다.
(operator new에 대해서는 [operator new / operator delete] 포스트를 참고하자.)
상식적으로 이 함수가 수행해야 할 일은 원래의 new가 수행해야할 메모리 할당 이다.
함수의 첫부분을 보면 m_ObjectList를 순회하면서 각각의 object중 현재 사용중이지 않은 메모리를 찾아서 반환해준다.
반환할 때에는 어떤 포인터가 들어있을지 모르기 때문에 void*로 반환하며 사용중 플래그를 true로 바꾼다.
만약 Object리스트의 모든 object들이 사용중 상태라면 메모리 블록을 하나 만들어서 기존 리스트에 추가한다.
( 이런일은 보통 생각했던것보다 많은 object를 생성하게되면 일어나는 상황이다. )
ReturnToFreeMemory
원래라면 메모리를 사용하고 나서 릭을 보지 않으려면 delete를 수행해야 할 것이다.
하지만 PoolManager를 사용하고 있는 프로그램에서는 delete를 하지 않고 사용가능 상태로만 만들어준다.
이유는 앞 포스트에서도 설명했듯이 메모리풀링을 하기 위해서이다.
1 2 3 4 | void CPoolingManager::ReturnToFreeMemory(void* object) { memset(object, 0, m_ObjectSize + 1); // memory 초기화 및 memory alive = false } | cs |
DeleteAllMemory
모든 메모리를 실제로 해제하는 함수이다. 게임을 종료하거나 Scene이 바뀌어서 더이상 메모리를 사용하지 않을때 릭을 방지하기 위해 호출한다.
게임을 종료하기전에는 무조건 호출해야한다. 현재는 Scene이 하나이기 때문에 PoolManager클래스의 소멸자에서 호출한다.
1 2 3 4 5 6 7 8 | void CPoolingManager::DeleteAllMemory() { for (auto obejct : m_ObjectList) { delete []obejct; } m_ObjectList.clear(); } | cs |
이상 포스트를 마친다.
'All > Project' 카테고리의 다른 글
ObjectManager (0) | 2016.04.12 |
---|---|
PoolingManager (0) | 2016.04.12 |
게임 전체 클래스 UML 및 간단설명 (0) | 2016.04.12 |
게임 개요 (0) | 2016.04.11 |
MemoryPooling_1 (0) | 2016.03.15 |