01.19

신승빈·2023년 2월 10일
0

KGCA 수업

목록 보기
107/128

IOCP

ERROR_NETNAME_DELETED

IOCP에서 Hardclose되는 경우 발생하는 error

Object Pool

IOCP나 Overlapped IO같은 경우 OVERLAPPED structure가 비동기 작업이 완료될 때 까지 객체가 유지되야 함
또한 너무 많은 Object가 동적으로 할당, 삭제를 반복할 경우 memory 유실이나 fragmentation의 문제가 발생할 수 있음
이를 방지하기 위해 사용이 끝난 memory를 재사용하는 기법

template<typename T>
class TObjectPool
{
public:
	enum
	{
		POOL_MAX_SIZE = 4096,				// 2^n
		POOL_SIZE_MASK = POOL_MAX_SIZE - 1,
	};
private:
	static void* m_mPool[POOL_MAX_SIZE];
	static long long m_HeadPos;
	static long long m_TailPos;
static void Allocation()
	{
		for (size_t i = 0; i < POOL_MAX_SIZE; i++)
		{
			// m_mPool[i] % MEMORY_ALLOCATION_ALIGNMENT = 0
			m_mPool[i] = _aligned_malloc(sizeof(T), MEMORY_ALLOCATION_ALIGNMENT);
		}
		InterlockedAdd64(&m_TailPos, POOL_MAX_SIZE);
	}
	static void Release()
	{
		for (size_t i = 0; i < POOL_MAX_SIZE; i++)
		{
        	// _aligned_malloc을 통해 할당된 메모리는 _aligned_free를 통해 해제해야 함
			_aligned_free(m_mPool[i]);
		}
	}
    
    // POOL_MAX_SIZE가 2^n이 되야하는 이유
    // POOL_SIZE_MASK는 입력값을 적절하게 순환하게 만들어주는 역할
	//POOL_SIZE_MASK = 0111
	//m_HeadPos = 0,  0000 & 0111 = 0
	//m_HeadPos = 1,  0001 & 0111 = 1
	//m_HeadPos = 2,  0010 & 0111 = 2
	//m_HeadPos = 3,  0011 & 0111 = 3
	//m_HeadPos = 4,  0100 & 0111 = 4
	//m_HeadPos = 5,  0101 & 0111 = 5
	//m_HeadPos = 6,  0110 & 0111 = 6
	//m_HeadPos = 7,  0111 & 0111 = 7
	 
	//m_HeadPos = 8,  1000 & 0111 = 0
	//m_HeadPos = 9,  1001 & 0111 = 1
	//m_HeadPos = 10, 1010 & 0111 = 2
    // ...
	static void* operator new (size_t size)
	{
		size_t pos = InterlockedIncrement64(&m_HeadPos)-1;
		size_t realpos = pos & POOL_SIZE_MASK;
        
        // 값 교환 atomic 함수
		void* ret = InterlockedExchangePointer(&m_mPool[realpos], nullptr);
		if (ret != nullptr)
		{
			return ret;
		}
		return _aligned_malloc(sizeof(T), MEMORY_ALLOCATION_ALIGNMENT);
	}
	static void operator delete (void* obj)
	{
		size_t pos = InterlockedIncrement64(&m_TailPos) - 1;
		size_t realpos = pos & POOL_SIZE_MASK;
		void* ret = InterlockedExchangePointer(&m_mPool[realpos], obj);		
		if (ret != nullptr)
		{
			_aligned_free(ret);
		}
	}
};

_aligned_malloc

메모리 할당 시 주소값이 지정된 크기로 나누어 떨어지도록 작업
Load/Store가 더 빠름

Reference : https://dataonair.or.kr/db-tech-reference/d-lounge/expert-column/?mod=document&uid=52449

직접 개발 시

Reference : https://univ-developer.tistory.com/entry/c6

Class Pool

virtual function을 갖는 class들은 vfptr을 추가로 가지므로 Object Pool과 같이 배열로 메모리 공간을 재사용 할 수 없음
여기서는 Queue를 사용하여 구현

template<typename T>
class TClassPool
{
public:
	TClassPool(size_t chunkSize = DefalultChunkSize);
	shared_ptr<T> NewChunk();
	void DeleteChunk(shared_ptr<T> obj);
protected:	
	size_t m_ChunkSize;
	static const size_t DefalultChunkSize = 10;
	std::queue<shared_ptr<T>> m_List;
};
template<typename T>
shared_ptr<T> TClassPool<T>::NewChunk()
{
	if (m_List.empty())
	{
		m_List.push(std::make_shared<T>());
		m_ChunkSize++;
	}
	auto chunk = m_List.front();
	m_List.pop();
	return chunk;
}
template<typename T>
void TClassPool<T>::DeleteChunk(shared_ptr<T> obj)
{
	m_List.push(obj);
}
profile
이상을 길잡이 삼아 로망을 추구합니다.

0개의 댓글