쿼리큘럼 개인적 정리

메모리 풀 / 프리리스트

MAKGA 2021. 10. 5. 22:57
320x100

메모리 풀은 미리 사용할 객체들을 할당해놓고 필요할 때 가져가고 사용 후엔 반환하며 쓰는 개념이다.

예전엔 다음과 같이 각 메모리들을 할당해두고 각 메모리에 다음 사용할 객체의 포인터 주소를 넣는 식으로 linked list로 구현한 버전을 찾아볼 수 있었다.

template <typename T, size_t ALLOC_COUNT>
class ObjectPool
{
    using uchar = unsigned char;
public:
    static void* operator new(size_t size)
    {
        ScopeLock sl(&lock_);

        if (nullptr == free_list_)
        {
            alloc();
        }

        auto* pAvailable = free_list_;	// 할당해주는 블럭은 free 목록에서 제외
        free_list_ = *reinterpret_cast<unsigned char**>(pAvailable);	// 할당하는 메모리가 다음으로 가리키던 메모리 가리킴
        ++cur_use_count_;

        return pAvailable;
	}

    static void	operator delete(void* obj)
    {
        ScopeLock sl(&lock_);
        --cur_use_count_;

        *reinterpret_cast<unsigned char**>(obj) = free_list_;	// 반환하는 메모리가 이전 free를 가리키고
        free_list_ = static_cast<unsigned char*>(obj);			// free를 반환하는 메모리로 설정
    }

    inline static int GetTotalCount() { return total_count_; }
    inline static int GetUseCount() { return cur_use_count_; }

protected:
    static void alloc()
    {
        free_list_ = new uchar[sizeof(T) * ALLOC_COUNT];
        uchar* pNext = free_list_;
        uchar** ppCurr = reinterpret_cast<uchar**>(free_list_);

        for (int i = 0; i < ALLOC_COUNT; ++i)
        {
            assert(sizeof(T) > sizeof(void*), "T ptr size must be greater than void* size are small.");

            pNext += sizeof(T);
            *ppCurr = pNext;	// 이전에 가리키던 블럭은 다음 블럭을 가리킨다
            ppCurr = reinterpret_cast<uchar**>(pNext);	// next가 또 움직여야 하니까 다음 블럭을 가리킨다.
        }

        *ppCurr = 0; ///< 마지막은 0으로 표시
        total_count_ += ALLOC_COUNT;
    }
private:
    static Lock lock_;
    static uchar* free_list_;
    static int total_count_;
    static int cur_use_count_;
};

template <typename T, size_t ALLOC_SIZE>
unsigned char* B2ObjectPool<T, ALLOC_SIZE>::free_list_ = nullptr;

template <typename T, size_t ALLOC_SIZE>
int B2ObjectPool<T, ALLOC_SIZE>::total_count_ = 0;

template <typename T, size_t ALLOC_SIZE>
int B2ObjectPool<T, ALLOC_SIZE>::cur_use_count_ = 0;

그치만 이젠 그럴 필요 있을까... 포인터 주소를 STL Queue 같은 컨테이너를 써서 관리하면 될거 같다.

320x100

'쿼리큘럼 개인적 정리' 카테고리의 다른 글

네트워크 장비 이해  (0) 2021.10.05
직렬화버퍼  (0) 2021.10.05
게임의 길찾기  (0) 2021.09.29
장르별 메시지 설계  (0) 2021.09.29
프로토콜 설계  (0) 2021.09.26