new를 호출하면 운영체제 커널에 메모리를 요청하게 되는데, 이때 컨텍스트 스위칭(context switching) 이 발생할 수 있다. 메모리를 자주 할당/해제하는 상황에서는 이 컨텍스트 스위칭이 성능 병목이 될 수 있다.
🔧 해결 방법: 한 번에 큰 메모리를 받아 놓고 사용자 레벨에서 쪼개서 관리하면 된다. → 메모리 풀(Pool) 기법
작은 크기의 메모리를 반복해서 할당/해제하다 보면 빈틈이 있는 메모리 공간이 많아지고, 사용할 수 있는 공간은 있지만 연속적이지 않아 할당 실패가 발생하는 문제가 생긴다.
🔧 해결 방법: 메모리를 효율적으로 관리할 수 있는 커스텀 할당자 작성
// Allocator.h
#pragma once
class BaseAllocator {
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);
}
malloc, free를 감싼 간단한 구조// CoreMacro.h
#ifdef _DEBUG
#define xalloc(size) BaseAllocator::Alloc(size)
#define xrelease(ptr) BaseAllocator::Release(ptr)
#else
#define xalloc(size) BaseAllocator::Alloc(size)
#define xrelease(ptr) BaseAllocator::Release(ptr)
#endif
xalloc, xrelease를 통해 메모리 할당을 더 간결하게 표현// Memory.h
#pragma once
#include "Allocator.h"
template<typename Type, typename... Args>
Type* xnew(Args&&... args)
{
Type* memory = static_cast<Type*>(xalloc(sizeof(Type)));
new(memory) Type(std::forward<Args>(args)...); // placement new
return memory;
}
template<typename Type>
void xdelete(Type* obj)
{
obj->~Type(); // 소멸자 직접 호출
xrelease(obj); // 메모리 해제
}
xnew: 메모리만 할당 후 생성자 호출xdelete: 소멸자 호출 후 메모리 반환placement new: 이미 할당된 메모리 위에 객체를 생성class Unit {
public:
Unit(int hp) : _hp(hp) {
cout << "Unit(hp)" << endl;
}
~Unit() {
cout << "~Unit()" << endl;
}
int _hp = 100;
};
int main() {
Unit* unit = xnew<Unit>(200);
xdelete(unit);
}
출력:
Unit(hp)
~Unit()
xnew와 xdelete가 new, delete와 동일한 기능을 수행하는 것을 확인new(memory) Type(args...);
new가 malloc + 생성자 호출이라면, placement new는 사용자 지정 메모리 + 생성자 호출| 문제 | 해결 방식 |
|---|---|
| 빈번한 컨텍스트 스위칭 | 한 번에 큰 메모리 요청, 유저레벨에서 분할 |
| 메모리 단편화 | 메모리 풀로 연속적인 공간 관리 |
new/delete가 느림 | 직접 메모리 관리 구조 작성 |
| 생성자 호출 제어 | placement new 사용 |