이 프로젝트는 C++에서 정적 타입과 동적 크기을 구현하는 라이브러리입니다. 메모리 풀은 메모리 재사용을 통해 메모리 할당과 해제를 최적화하여 성능을 향상시키며, 메모리 관리를 효율적으로 처리합니다. 모든 메모리 풀의 생성(create), 할당(alloc), 해제(dealloc)은 CMemoryPoolManager를 통해서만 가능합니다.
할당(alloc)의 경우, 이 프로젝트는 수동 메모리 관리 방식과 직접 구현한 CSharedPtr를 이용한 자동 메모리 관리 방식 두 가지를 제공합니다.
- 수동 메모리 관리 방식은 특정 메모리 풀을 명시적으로 제어하고 즉시 해제할 수 있어, 성능 최적화와 유연한 메모리 관리가 가능합니다.
- 자동 메모리 관리 방식은
CSharedPtr를 통해 여러 곳에서 특정 메모리를 공유하다가 더 이상 사용하지 않으면 메모리를 자동으로 해제하여 안전한 메모리 관리가 가능합니다.
이 두 방식은 각각의 특징에 따라 선택적으로 사용할 수 있도록 구현되어 있으며, 필요에 따라 메모리 제어의 유연성을 제공합니다.
모든 메모리 풀의 기본 인터페이스이자 추상화 클래스입니다. CMemoryPoolManager는 void*로 메모리 풀을 관리할 수 없으므로, IMemoryPool를 사용하여 T타입에 안전하게 메모리 풀을 관리합니다. 이를 통해 CStaticMemoryPool<T>의 소멸자가 제대로 호출될 수 있습니다.
T타입의 객체를 위한 정적 메모리 풀을 관리하는 클래스입니다. 이 클래스는 다음과 같은 주요 기능을 제공합니다.
- 타입별 메모리 풀 관리:
T타입의 객체를 위한 전용 메모리 풀을 유지합니다. 각 타입에 대해 별도의 메모리 풀이 생성되며, 메모리 관리가 효율적입니다. - 동적 크기 조정: 메모리 풀의 크기는 동적으로 조정됩니다. 초기 크기는
CMemoryPoolManager를 통해CStaticMemoryPool<T>의 생성자에서 설정할 수 있으며, 필요에 따라 메모리 풀이 확장되며, 초기 크기만큼의 메모리 블록이 추가됩니다. - 효율적인 메모리 할당 및 해제:
Allocate():std::stack을 이용하여 빈 블록의 인덱스를 관리하므로, 메모리 풀에서 가장 앞쪽 또는 가장 최근에 해제된 사용 가능한 메모리 블록이 우선적으로 할당됩니다. 만약 사용 가능한 블록이 없으면,ExpandPool()를 호출하여 메모리 풀을 확장하며, 새로운 메모리 블록이 추가되고 빈 블록의 인덱스가 스택에 저장됩니다.Deallocate(T* deallocPtr): 할당된 메모리 블록을 해제합니다. 해제된 블록은 다시 재사용할 수 있도록std::stack에 추가됩니다. 이를 통해 메모리 재사용을 최적화하고, 메모리 할당/해제 성능을 향상시킵니다. 만약 모든 메모리 블록이 반환되면, 함수 내부에서IsPoolUnused()를 통해 확인한 후DeletePool()을 호출하여 해당 풀을 삭제합니다.
- 메모리 확장:
ExpandPool()는 새로운 메모리 블록을 할당하고, 이를 메모리 풀에 추가합니다. 새로 할당된 메모리 블록의 인덱스는 스택에 추가되어, 후속 메모리 요청에 대비합니다. - 범위 확인:
IsWithinRange(T* ptr, T* start, T* end)는 주어진 포인터가 메모리 블록의 유효 범위 내에 있는지 확인합니다. 이 함수는 메모리 블록의 시작과 끝 사이에 포인터가 위치하는지 검사하는 데 사용됩니다.
모든 메모리 풀의 생성, 할당, 해제를 관리하는 싱글턴 클래스입니다. 이 클래스는 다음과 같은 주요 기능을 제공합니다. 이 클래스는 다양한 타입의 메모리 풀을 생성하고 관리할 수 있도록 설계되었습니다.
- 메모리 풀 생성:
CreatePool<T>(int initCapacity)를 통해 타입T에 대한 메모리 풀을 생성합니다. 초기 용량은initCapacity로 설정할 수 있으며, 이미 생성된 풀은 재생성되지 않습니다. - 메모리 풀 삭제:
DeletePool<T>()를 사용하여 타입T타입의 메모리 풀을 삭제합니다. 풀을 삭제하면 해당 타입에 대한 메모리 풀도 해제됩니다. - 메모리 할당 및 해제:
CMemoryPoolManager를 통해Allocate<T>()를 사용하여 타입T의 객체를 위한 메모리를 할당하고,Deallocate<T>(T* ptr)를 사용하여 메모리를 해제합니다. 할당과 해제는 모두CStaticMemoryPool<T>를 통해 처리됩니다. - 싱글턴 인스턴스 관리:
GetInst()를 통해CMemoryPoolManager의 유일한 인스턴스를 가져오고,DestroyInst()를 통해 인스턴스를 삭제합니다. 인스턴스를 삭제하면, 모든 생성된 메모리 풀도 자동으로 삭제되어 메모리 누수를 방지하고, 메모리 관리를 간편하게 합니다.
int main()
{
// Player 타입을 위한 크기 100의 메모리 풀 생성
CMemoryPoolManager::GetInst()->CreatePool<Player>(100);
// Player 타입의 메모리 풀에서 사용 가능한 메모리 블록의 포인터를 반환
Player* ptr = CMemoryPoolManager::GetInst()->Allocate<Player>();
// 메모리 풀에 사용된 ptr의 메모리 블록을 반환하여 재사용 가능하게 함
CMemoryPoolManager::GetInst()->Deallocate(ptr);
// Player 타입의 메모리 풀 삭제
CMemoryPoolManager::GetInst()->DeletePool<Player>();
// 메모리 풀 매니저 인스턴스 삭제
CMemoryPoolManager::DestroyInst();
return 0;
}위 코드는 Player 타입의 메모리 풀을 크기 100으로 생성하고, 메모리 풀에서 미리 할당해놓은 사용 가능한 메모리 블록의 포인터를 반환받아 ptr 변수에 저장한 후, 다시 메모리 풀에 반환하여 재사용 가능하게 만드는 과정입니다. 이후 생성한 메모리 풀을 삭제하고, 마지막으로 메모리 풀 매니저 인스턴스를 삭제하면 존재하는 모든 메모리 풀도 함께 삭제됩니다.
// CSharedPtr를 사용하려는 클래스 객체는 반드시 CRefCounter를 상속받아야 합니다.
int main()
{
// Player 타입을 위한 크기 100의 메모리 풀 생성
CMemoryPoolManager::GetInst()->CreatePool<Player>(100);
// Player 타입의 메모리 풀에서 사용 가능한 메모리 블록의 포인터를 반환
Player* playerPtr = CMemoryPoolManager::GetInst()->Allocate<Player>();
CSharedPtr<Player> ptr1 = playerPtr; // refCount: 1
CSharedPtr<Player> ptr2 = playerPtr; // refCount: 2
ptr1 = nullptr; // refCount: 1
// 자동으로 메모리 관리 및 메모리 풀에 메모리 반환
ptr2 = nullptr; // refCount: 0
// 메모리 풀 매니저 인스턴스 삭제
CMemoryPoolManager::DestroyInst();
return 0;
}위 코드는 Player 타입의 메모리 풀을 크기 100으로 생성하고, 해당 메모리 풀에서 사용 가능한 메모리 블록을 CSharedPtr<Player>로 할당받아 ptr1과 ptr2 변수에 대입한 뒤, 모든 변수와의 연결이 끊기면 CSharedPtr와 CRefCounter를 통해 자동으로 메모리 관리 및 메모리 풀에 반환하는 과정입니다. 이후 생성한 메모리 풀을 삭제하고, 마지막으로 메모리 풀 매니저 인스턴스를 삭제하면 존재하는 모든 메모리 풀도 함께 삭제됩니다.