사실 나의 졸작게임 서버를 만드는 것에는 new와 delete를 남발해도 별일이 일어나지는 않는다.
어차피 2명만 수용하면 되기 때문이다..
하지만 실제 게임 서버에서는 런타임 동적할당을 절대 사용해서는 안된다고 한다.
오랫동안 살아있는 채로 돌려야 하는데 메모리를 만들고 지우고를 계속하다가 메모리가 파편화돼서 그런 것 같기도 하고,
new와 delete의 부하도 심해서 그런 것 같기도 하고,
정확한 이유는 모르겠지만 확실히 서버가 돌아가는 중에 동적할당을 써서 좋을 것은 없을 것 같다.
그래서 대게 이 문제를 메모리풀이나 오브젝트풀을 활용하여 해결한다고 한다.
오브젝트풀은 말그대로 오브젝트(클래스로부터 실체화된 친구들)들이 모여있는 곳으로, 초기화 단계에서 미리 왕~~~창 만들어두고 필요할 때는 꺼내 쓰고 필요 없으면 반납하는 형식으로 할당 없이 돌려쓰기 하는 것이다.
원리처럼 구현도 간단하다.
구현 중에 중요한 것은 확장인데, 오브젝트 풀이 비었을 때 사용을 해야 한다면 개수만큼 새로 만들어서 채워주는 것이다.
나는 이 objectPool을 구현하기 위해 STL Stack를 사용했다.
사실 자료형은 어떤 자료형을 해도 구현이 가능하다. 보통은 list를 사용하는 듯하다.
소스는 주석만 봐도 될 만큼 간단해서 따로 설명은 안 적어도 될 것 같다.
특이사항이 있다면, 서버라 Thread-Safe하게 하기 위해서 lock을 걸었다.
lock-free한 자료형을 만드려고 했지만 아직은 성공하지 못했다.. OTL
#pragma once
#include <stack>
#include <mutex>
typedef std::lock_guard<std::recursive_mutex> MutexLocker;
template<typename T>
class CObjectPool
{
public:
// 사이즈만큼 오브젝트를 만든다.
CObjectPool(int size = 100) {
_maxSize = size;
for (int i = 0; i < _maxSize; ++i) {
T* newObject = new T();
_objects.push(newObject);
}
}
// 오브젝트를 비운다.
~CObjectPool()
{
MutexLocker locker(_mt);
while (!_objects.empty()) {
T* object = _objects.top();
_objects.pop();
delete object;
}
_maxSize = 0;
}
// 오브젝트를 꺼낸다.
T* PopObject()
{
MutexLocker locker(_mt);
// 오브젝트가 없다면 확장한다.
if (_objects.empty()) {
Expand();
}
T* retVal = _objects.top();
_objects.pop();
return retVal;
}
// 현재 크기만큼 새로운 오브젝트를 넣어 확장한다.
void Expand() {
MutexLocker locker(_mt);
// 늘린 크기만큼 새로운 오브젝트를 넣어준다.
for (int i = 0; i < _maxSize; ++i)
{
T* newObject = new T();
_objects.push(newObject);
}
// 최대 크기를 늘린다.
_maxSize += _maxSize;
}
// 오브젝트를 수거한다.
void ReturnObject(T* object)
{
MutexLocker locker(_mt);
_objects.push(object);
}
private:
std::recursive_mutex _mt;
std::stack<T*> _objects;
int _maxSize; // 최대 배열 크기
};
오브젝트 풀을 쓰는 것 말고도 메모리를 미리 할당하고 여러 오브젝트로 나누는등 여러 방법도 있는 것 같으니 나중에 꼭 찾아봐야겠다.
--------------------------------------------------------------------------------------------------------------
!! 위 코드는 실제로 사용하기에 매우 비효율적이라서 다시 한번 작성해 보았습니다... !!
'졸업 작품 > 서버' 카테고리의 다른 글
TCP / UDP 패킷 분리(Split) 현상 합치기 (4) | 2019.06.01 |
---|---|
C++ IOCP 서버 3. IOCP 구현 (작동부) (6) | 2019.05.16 |
C++ IOCP 서버 3. IOCP 구현 (초기화) (2) | 2019.05.15 |
C++ IOCP 서버 2. IOCP 이론 (0) | 2019.05.10 |
C++ IOCP 서버 1. 동기 비동기 (0) | 2019.05.10 |