프로젝트/GameServerCore

Stomp Allocator

춤추는수달 2022. 4. 2. 07:17

Stomp Allocator는 기존의 new, delete의 메모리 오염 문제를 해결하기 위해 정의한 클래스이다.

 

메모리 오염

메모리 오염이란 메모리가 해제되었는데도 잘못 사용되는 문제를 말한다. 예를 들면 아래와 같은 상황에서 발생할 수 있다.

class Knight
{
public:
	Knight() { _hp = 100; }
	Knight(int hp) :_hp(hp){}
	~Knight() {}
	int _hp;
};
int main()
{
	Knight* test = new Knight();
	test->_hp = 100;
	delete test;
	test->_hp = 200; //여기!
}

마지막 줄에서 이미 해제된 포인터인 test의 멤버 변수 값을 수정하고 있다. 명백히 잘못된 코드이지만 이 코드는 실제로 실행이 된다.  그 이유는 코드 상에서 delete가 실행됐지만 사실은 최적화 등의 사유로 진짜 메모리가 사용 불가능한 상태가 되지는 않았기 때문이다. 이러한 문제를 use after free, 또는 dangling pointer 문제라고도 한다.

꼭 이런 상황에서 뿐만 아니라, 컨테이너가 clear 된 이후에 사용했거나, 부모 클래스로 생성된 객체를 자식 클래스로 캐스팅 후 자식 클래스의 멤버 변수를 변경하는 등의 상황에서도 발생한다.

 

Stomp Allocator를 사용한 해결 방법

이 문제를 해결하기 위해서는 여러 방법이 있지만, 여기서는 Stomp Allocator를 사용해 해결해보자. 여기서 Stomp Allocator란 단순히 c++ 표준에 있는 VirtualAlloc, VirtualFree 함수를 사용한 메모리 할당, 해제를 해주는 클래스를 의미한다.

VirtualAlloc, VirtualFree 함수는 new, delete와 달리 실행되는 즉시 할당, 해제가 완료되기 때문에 상기한 메모리 오염 문제가 발생하지 않는다. 그러나 이 VirtualAlloc함수는 메모리 할당 시 페이지 크기 단위로만 할당해준다. 즉 메모리 효율이 굉장히 구리다. 따라서 이 Stomp Allocator는 디버그 환경에서만 사용해주도록 할 것이다.

또한 페이지 크기 단위로 할당하다 보니 실제 필요한 공간보다 할당된 공간이 커서 오버플로우가 발생되어도 문제없이 실행된다는 문제가 발생한다. 그래서 Alloc 함수 반환 시 할당된 공간 끝에 필요한공간이 딱 오도록 offset을 계산해서 반환할 것이다. 반대로 Release 함수에서는 원래 할당된 주소를 계산하여 해제하도록 해야한다.

void* StompAllocator::Alloc(int32 size)
{
	//페이지 갯수 구하기
	const int pageCount = (size + PAGE_SIZE - 1) / PAGE_SIZE;
	//오버플로우 방지용 오프셋 설정
	const int64 dataOffset = pageCount * PAGE_SIZE - size;
	//메모리 예약과 동시에 사용, 읽기쓰기 가능
	void* baseAddress = VirtualAlloc(NULL, pageCount * PAGE_SIZE, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
	return static_cast<void*>(static_cast<int8*>(baseAddress) + dataOffset);
}

void StompAllocator::Release(void* ptr)
{
	const int64 address = reinterpret_cast<int64>(ptr);
	//할당했던 메모리 첫 부분으로 이동
	const int64 baseAddress = address - (address % PAGE_SIZE);
	VirtualFree(reinterpret_cast<void*>(baseAddress), 0, MEM_RELEASE);
}

 

 

 

'프로젝트 > GameServerCore' 카테고리의 다른 글

ServerCore  (0) 2022.10.05
네트워크 라이브러리  (0) 2022.05.30
STL Allocator  (0) 2022.04.04
DeadLockProfiler  (0) 2022.02.18
ReadWrite Lock  (0) 2022.02.14