메모리 할당하는 것 자체는 결국 운영체제가 관리를 해주는 영역이므로, 경우에 따라 우리가 메모리를 요청하기 위해 계속해서 커널 레벨로 컨텍스트 스위칭을 하는 등의 형태로 동작할 수도 있다. 컨텍스트 스위칭은 비용이 큰 작업이므로, 이런 식으로 계속 스위칭을 하는 방법의 대안으로 나온 것이 메모리 풀링이다. 애초에 크게 할당받아서 유저 레벨에서 나눠서 쓰는 방법이다. 필수는 아니지만 한 번 살펴보자! 🏊🏻
new
, delete
연산자도 오버로딩 대상이 될 수 있다. 아래는 예시이다!
static void* operator new(size_t size)
{
cout << "new!" << size << endl;
void* ptr = ::malloc(size);
return ptr;
}
static void operator delete(void* ptr)
{
cout << "delete!" << endl;
::free(ptr);
}
이렇게 커스텀으로 사용할 것이라면 전역으로 사용하는 대신 우리가 직접 지정해주는 편이 좋다.
placement new : 이미 할당된 메모리에서 객체의 생성자를 호출할 수 있다.
Type* memory = static_cast<Type*>(BaseAllocator::Alloc(sizeof(Type))); // placement new new(memory)Type(); return memory;
// Allocator.h
class Allocator
{
public:
static void* ALloc(int32 size);
static void Release(void* ptr);
};
// Allocator.cpp
void* BaseAllocator::Alloc(int32 size);
{
return ::malloc(size);
}
void BaseAllocator::Release(void* ptr)
{
::free(ptr);
}
int main()
{
Knight* knight = xnew<Knight>();
xdelete(knight);
}
// memory.h
#include "Allocator.h"
template<typename Type, typename... Args)
Type* xnew(Args&&... args)
{
Type* memory = static_cast<Type*>(BaseAllocator::Alloc(sizeof(Type)));
// placement new
new(memory)Type();
return memory;
}
template<typename Type>
void xdelete(Type* obj)
{
BaseAllocator::Release(obj);
}