서버/메모리 관리 8

8. Object Pool

저번의 메모리 풀에는 뭔가가 아쉬운 부분이 있다. 직접 구현한 메모리 풀에서는 사이즈가 비슷한 객체들을 하나의 풀에 넣어서 관리를 했다. 사이즈가 조금이라도 다른 객체들이 같은 풀에 있다보니 해당 풀에서 메모리 오염이 발생할 가능성이 있다. 만약 어떤 한 클래스에서 오류가 났다면 그 클래스의 코드만 살펴보면 되지만 이런 경우 어디서 오류가 발생했는지 탐지하기도 굉장히 힘들다. 그래서 이번에 알아볼 것이 오브젝트 풀이다. 생각해보면 알겠지만 메모리 풀이 오브젝트 풀의 상위 개념이다. 오브젝트 풀을 포함하고 있다는 것이다.  ObjectPool.h#pragma once#include "Types.h"#include "MemoryPool.h"templateclass ObjectPool{public: templ..

7. Memory Pool #2

ABA Problem이라는 것이 있다. CAS(Compare And Swap)에서 오류를 감지하지 못하는 것인데 쉽게 예시를 설명하자면 이렇다. 10 -> 20 -> 30 과 같이 리스트로 연결된 데이터가 있다고 하자.A 스레드가 CAS를 이용하여 제일 앞의 10을 40으로 바꾼다고 해보자. 그렇다면 10 -> 20 -> 30이라는 리스트를 저장 후 '만약 제일 앞의 데이터가 10이면 40으로 바꾸어라' 이렇게 작동할 것이다. 하지만 멀티스레드 환경에서 CAS를 실행하기 전 다른 여러 스레드에서 pop 2번이 일어나 10과 20의 메모리가 반환 되고, push 1번 일어나서 10이라는 메모리를 재활용해 다시 할당 받았다고 가정하여 10 -> 30이 되었다고 생각해보자. 그렇게 되면 제일 앞의 데이터는 1..

6. Memory Pool #1

지금까지는 필요할 때 메모리를 할당하고 사용이 끝나면 해제하였다. 하지만 매번 할당하고 해제하는 것이 비효율적이라고 느낄 수도 있고 메모리 단편화에 대한 문제도 있다.(요즘은 할당기가 잘 되어 있어 단편화에 대한 문제는 크게 신경쓸 필요는 없다고 한다.) 풀이라는 것은 직역하면 수영장 뭐 이런 뜻인데 수영장에 물을 담아놓는 것처럼 메모리를 담아놓았다가 필요할 때 꺼내 쓰는 것이다. 메모리를 사용하고 해제하는 것이 아니라 그냥 풀에 스윽 던져놓는 것이다. 그래서 매번 할당하고 해제할 필요성이 없다. 객체단위로 풀링을 하는 오브젝트 풀링이라는 것을 들어보았을 것이다. 하지만 우리가 동적할당할 것들은 객체뿐만 아니라 벡터, 맵 등 다양한 자료구조에 대해서도 동적할당을 해야한다. 이런 상황(크기가 일정하지 않음..

5. STL Allocator

일반적인 클래스나 자료형은 지금까지 했던 Allocator를 이용하여 메모리를 할당하고 해제할 수 있었다. 메모리 오염 또한 방지할 수 있었는데 벡터나 맵 등 다른 자료구조에 대해서는 아직 내부적으로 new, delete를 사용하고 있을 것이다. 이번에는 이를 한 번 수정해보자.벡터 클래스의 선언부를 보면 타입과 Allocator를 지정할 수 있다.vector> v;이런식으로 사용할 수 있다는 뜻이다!!! 하지만 매번 위와 같이 지정할 수는 없으므로 헤더파일을 하나 만들어보자. Container.h#pragma once#include "Types.h"#include "Allocator.h"#include #include #include #include #include #include #include #i..

4. Stomp Allocator

메모리가 이미 해제되었는데 사용하거나 사용할 수 있는 범위를 넘어서 사용하는 등 유효하지 않은 메모리 영역에 접근하는 것을 메모리 오염이라고 한다. 메모리 오염의 경우 크래시가 나지 않을 때도 있어 프로그램에 치명적일 수 있다. 예를 들어 허용된 범위를 넘어 메모리에 접근을 했는데 이미 다른 객체가 사용중인 메모리라던가 아니면 게임같은 경우 골드와 같이 유료재화를 담당하는 메모리라고 생각해보자. 이러한 상황을 예방하기 위한 것이 바로 Stomp Allocator이다. Allocator.h//-------------------// StompAllocator//-------------------class StompAllocator{ enum { PAGE_SIZE = 0x1000 }; // 4kbpublic..

3. Allocator

메모리를 관리하기 위해서 일반적으로 new와 delete를 사용한다. 하지만 메모리를 사용하고 반납하는 과정에서 조각난 공간들이 생기게 되고 그렇게 되면 분명 빈 메모리가 있음에도 제대로 사용할 수 없는 상황이 생기게 된다. 이런 상황을 메모리 단편화라고 한다. 이러한 상황을 예방할 수 있는 메모리풀을 구현하기 위한 초석으로 간단하게 new와 delete를 새롭게 만들어 보자. Allocator.h#pragma once//------------------// BaseAllocator//------------------class BaseAllocator{public: static void* Alloc(int32 size); static void Release(void* ptr);};Allocator.c..

2. 스마트포인터

스마트포인터는 동적 메모리를 관리하는 클래스이다. 일반적인 포인터와 똑같이 사용할 수 있지만 프로그래머가 직접 메모리 해제를 해주어야하는 포인터와 달리 스마트포인터는 알아서 메모리를 해제해준다. 스마트포인터는 3가지 종류가 있다. 1) unique_ptrunique_ptr ptr1 = make_unique(10);unique_ptr ptr2(new int(10));unique_ptr은 위와 같이 사용할 수 있고 unique라는 단어 뜻 그대로 다른 포인터가 해당 객체를 가르킬 수 없다. 그래서 복사도 불가능하다. 따라서 move와 같은 함수를 사용하여 객체의 소유권을 완전히 넘겨주는 식으로만 동작한다. 2) shared_ptrshared_ptr ptr1 = make_shared(10);shared_ptr..

1. Reference Counting

객체를 생성시키고 소멸시킬 때 문제점이 있다. A라는 객체가 B라는 객체를 참조하고 있는 경우 B라는 객체가 용도를 다해서 소멸시키게 되면 A는 이상한 메모리 공간을 참조하게 되어버린다. 이를 해결하기 위해 Reference Counting을 하는데 자신을 참조하고 있는 수를 센 후 0이 되었을 때 소멸시키는 것이다. 코드를 보면 더욱 이해하기 쉬울 것이다.RefCounting.h#pragma once//-----------------// RefCountable//-----------------class RefCountable{public: RefCountable() : _refCount(1) {} virtual ~RefCountable() {} // 최상위 클래스의 소멸자에는 virtual(메모리 릭..