챕터3 부터는 조금씩 난도가 높은 내용이 나오기 시작한다. 내용에 따라 하나 또는 몇개 섹션을 묶어서 리뷰해야 할 것 같다.


메모리풀은 OS의 메모리 할당/반환 과정을 최대한 줄이기 위한 기법으로 다양한 분야에서 다양한 방법으로 활용되고 있다.


본 교재에서는 템플릿과 정적 변수를 활용하여 메모리 할당/반환이 필요한 클래스 각각의 메모리풀을 따로 관리하도록 되어 있다. 아래와 같이 CData 클래스가 있다면


class CData
{
    int a[1000];
    int b[1000];
};



이 클래스에 메모리풀 클래스를 상속하여 아래와 같은 클래스로 변환하면 메모리풀 클래스가 완성된다.


class CDataMP : public CMemoryPool<CDataMP>
{
    int a[1000];
    int b[1000];
};

CMemoryPool의 내용은 생각보다 간단하다. new/delete를 오버라이딩하고, static 포인터 하나를 두어 메모리풀이 내어줄 메모리 블록의 위치를 표시해준다.


여기서 내가 놀란 부분은 CMemeryPool의 메모리블록체인의 연결 방식이었다. 기본적으로는 Linked List를 표방하고 있다. 즉, 풀 내에 블록체인을 가지고 있다가 할당 요청이 들어오면 할당 수 만큼 체인에서 블록을 떼어주고, 반납 시에는 체인 맨앞부분에 다시 연결을 해주는 것이다. (뒤가 아닌 앞에 연결하는 이유는 아직 모르겠다.)


여기까지는 누구나 생각할 수 있다고 본다. 하지만, 체인을 연결하는 방식에서 저자의 내공을 엿볼 수 있었다. 바로, 메모리 블록 자체에 체인 정보를 넣는 것이었다. 아래와 같다.




즉, 블록 맨 앞의 4~8바이트 공간을 체인 정보 저장 공간으로 활용하고 있다. 메모리는 반환하게 되면 어차피 내용은 무엇이 되어도 상관이 없기 때문에 가능한 방법이다. 이렇게 되면 별도의 관리 공간이 불필요하게 되어, 군더더기 없는 깔끔한 자료구조가 나오게 된다. (나는 개인적으로 이런 작은 차이에서 고수와 하수가 나뉜다고 믿는다.)


메모리풀의 성능은 교재에서 측정한 당시 2006년 약 10배 정도의 속도의 이득을 볼 수 있었다고 기술되어 있다. 그도 그럴 것이 new/delete는 내부적으로 쭉 타고 들어가면 종국에는 malloc()/free()를 발생시키는데, 이들이 OS primitive 즉, system call이기 때문에 유저 영역과 커널 영역을 넘나들게 된다. 이에 대한 오버헤드가 상당히 크기 때문에 위와 같은 성능 차이가 나오게 되는 것이다.


이 형태의 메모리풀이 활용되기 위해서는 클래스 설계 시 복잡한 ADT 구조를 가지지 못하도록 해야한다. 멤버 중 포인터가 있다면 이 기법을 활용하기 어렵다. 그러므로, 큰 그림을 가지고, 메모리풀을 활용할 부분과 그렇지 않은 부분을 잘 선택하여 설계해야 하겠다.


한가지 첨언을 하자면 근래의 OS들은 OS 자체에서 Memory Pool 기능을 제공한다고 한다. 그에 대한 활용 방안도 차후에 살펴봐야겠다.



Posted by JMAN