Coding Memo
메모리 할당 - Allocator 본문
본 포스팅은 인프런에 등록되어 있는 Rockiss 님의 강의를 보고 간단하게 작성한 글입니다.
C#, Java 등은 메모리관리를 알아서 해주지만 C++은 직접 해야할 필요가 있다. (new-delete)
new-delete를 그대로 사용하지 않고 오버로딩 하듯이 바꿔서 사용하여 메모리를 할당(allocate)하고 해제(free)를 한다.
그 이유는
1. new를 할 때마다 메모리 할당을 커널에 요청하기 위해 컨텍스트 스위칭(context switching)이 빈번하게 일어날 수 있다.
-> 성능 저하 발생 가능성
2. 사이즈가 각각 다른 할당된 메모리들에서 몇몇 부분이 해제되었을 경우, 사용할 수 있는 빈공간이 생기는데 메모리 구조상 이어저 있지 않은 경우 비어 있는 메모리 공간 이상의 사이즈를 가진 메모리를 새로 할당하지 못하여 메모리 낭비가 일어날 수 있다. (메모리 단편화)
따라서 메모리를 크게 할당한 뒤에 유저레벨에서 나눠서 쓰는 방법 (Memory Pool)을 사용한다.
(반드시 이미지처럼 되는 것은 아니고, 어느정도 관리는 해주기 때문에 필수적으로 사용해야되는 기법은 아니다.)
Allocater 생성
기본적으로 C에서 사용했던 malloc 함수와 free 함수를 이용
#pragma once
class BaseAllocator
{
public:
static void* Alloc(int size);
static void Release(void* ptr);
};
#include "pch.h"
#include "Allocator.h"
void* BaseAllocator::Alloc(int size)
{
return ::malloc(size);
}
void BaseAllocator::Release(void* ptr)
{
::free(ptr);
}
new, delete를 새로 작성
기존 new와 delete를 구별하기위해 xx를 앞에 붙여서 작성하였다.
생성자 호출과 소멸자 호출도 빼먹지 말자.
#pragma once
#include "Allocator.h"
using namespace std;
template<typename Type, typename... Args>
Type* xxnew(Args&&... args)
{
Type* memory = static_cast<Type*>(BaseAllocator::Alloc(sizeof(Type)));
new(memory)Type(forward<Args>(args)...); // placement new
return memory;
}
template<typename Type>
void xxdelete(Type* obj)
{
obj->~Type();
BaseAllocator::Release(obj);
}
xnew와 xdelete를 편하게 사용하기 위해 매크로로 등록하자
// CoreMacro.h
#ifdef _DEBUG
#define xxalloc(size) BaseAllocator::Alloc(size)
#define xxrelease(ptr) BaseAllocator::Release(ptr)
#else
#define xxalloc(size) BaseAllocator::Alloc(size)
#define xxrelease(ptr) BaseAllocator::Release(ptr)
#endif // _DEBUG
xnew와 xdelete내의 함수도 매크로로 바꾸면...
#pragma once
#include "Allocator.h"
using namespace std;
template<typename Type, typename... Args>
Type* xxnew(Args&&... args)
{
Type* memory = static_cast<Type*>(xxalloc(sizeof(Type)));
new(memory)Type(forward<Args>(args)...); // placement new
return memory;
}
template<typename Type>
void xxdelete(Type* obj)
{
obj->~Type();
xxrelease(obj);
}
참고: 매크로 함수를 xalloc이나 xrelease로 하면 오류가 발생할 수 있다. 다른 파일에서 이미 xalloc과 xrelease가 정의되어 있어 그 파일을 참조하고 있는 코드가 있을 경우 빌드에 오류가 발생할 수 있다.
테스트 코드
#pragma once
#include <iostream>
#include "CoreMacro.h"
#include "Allocator.h"
#include "Memory.h"
using namespace std;
class Unit
{
public:
Unit()
{
cout << "Unit()" << endl;
}
Unit(int hp) : _hp(hp)
{
cout << "Unit(hp)" << endl;
}
~Unit()
{
cout << "~Unit()" << endl;
}
int _hp = 100;
};
int main()
{
Unit* unit = xxnew<Unit>(10);
xxdelete(unit);
}
실행결과
new와 delete와 마찬가지로 생성자, 소멸자도 제대로 호출이 된다.
'Game Server (C++)' 카테고리의 다른 글
Memory Pool (0) | 2022.10.09 |
---|---|
메모리 할당 - STL Allocator (0) | 2022.10.09 |
메모리 할당 - Stomp Allocator (0) | 2022.10.06 |
Reference Counting (0) | 2022.09.30 |
Lock 구현 (Read-Write Lock) (1) | 2022.09.26 |