Skip to content
mooneegee edited this page Feb 18, 2014 · 1 revision

소프트웨어의 성능은 알고리듬과 메모리 활용에 의해 결정된다. 메모리가 성능에 영향을 끼치는 형태는 다음과 같다.

  1. 동적 메모리 할당, malloc이나 C++의 전역 new 연산자는 매우 느리다. 동적 메모리 할당을 피하거나 할당하는 비용을 줄일 수 있는 allocator(동적 할당자)를 직접 만들어야 한다.
  2. memory access pattern(메모리 접근 패턴)에 좌우되는 경우도 많다. 시스템 아키텍쳐 시간에 배운 memory locality를 생각하면 쉽게 이해할 수 있다.

동적 메모리 할당 최적화

heap allocation(malloc(), free(), C++의 전역 new 연산자 및 delete 연산자 등)은 매무 느리다. 느린 원인은 두 가지이다.

  • 힙 할당자는 범용 목적이기 때문에 1바이트에서 수 기가까지 어떤 크기의 할당이라도 처리할 수 있어야 하는데 이렇게 하면 관리하는 부가적인 비용이 든다.
  • malloc()과 free()를 호출할 때 대부분 운영체제에서는 먼저 유저 모드에서 커널 모드로 context-switch를 하고, 필요한 동작을 수행한 후 다시 프로그램으로 context-switch을 해야 한다. windows 실습 시간에 context-switch를 수행할 때 발생하는 비용에 대해서 배웠으니 교재를 참고하길 바란다.

그래서 다음을 반드시 지키기위해서 노력해야 한다. 게임 개발에 있어서 Golden Rule이라고 한다.

힙 할당은 최소화하고 tight loop 안에서는 절대 힙 할당을 하지 말 것!

그런데 현실적으로 동적 메모리 할당을 전혀 하지 않기란 불가능하다. 해결책은 allocator를 제작해서 쓰는 것이다. allocator의 장점은 다음과 같다.

  • 미리 할당된 메모리 블록을 이용할 수 있다. 이 경우 운영체제의 커널 모드로 context-switch가 필요없이 유저 모드에서만 동작하는 이점이 있다.
  • 사용 패턴을 예측할 수 있기 때문에 범용 힙 할당자에 비해 훨씬 효율적으로 동작할 수 있다.

allocator에 관한 정보 click!

스택 기반 할당자

stack에 관한 설명은 생략하겠다. marker는 top-pointer를 roll-back할 때 필요하다. 할당된 두 블록의 정확한 경계 지점이 있어야 해제할 때 top-pointer를 어디로 내릴지 알 수 있기 때문이다. 그래서 스택 할당자는 보통 현재 스택 꼭대기를 나타내는 marker를 리턴하는 함수를 제공한다. top-pointer를 내리는 roll-back함수는 marker를 함수의 인자로 받는다.

class StackAllocator
{
public :
    // 스택 마커 : 현 시점의 스택 꼭대기를 나타낸다.
    // 롤백할 때는 임의의 주소로 할 수 없고 반드시 marker의 위치로만 할 수 있다.
    typedef U32 Marker;

    // 전체 크기를 인자로 받아 스택 할당자를 생성한다.
    explicit StackAllocator(U32 stackSize_bytes);

    // 스택의 꼭대기에 주어진 위치만큼 할당한다.
    void * alloc(U32 size_bytes);

    // 현재 스택의 꼭대기를 표시하는 마커를 리턴한다.
    Marker getMarker();

    // 이전의 마커 위치로 롤백한다.
    void freeToMarker(Marker marker);

    // 스택 전체를 비운다.(스택을 0의 위치로 롤백한다.)
    void clear();
private :
    // ...
};

풀 할당자

  • Memory leak
    할당된 메모리가 제때 해제되지 않는 것으로 out of memory를 초래할 수 있다.

  • Memory corruption
    엉뚱한 메모리 주소를 변경해 원래 있던 정보를 날려 버리고 정작 변경됐어야 할 메모리 위치의 값은 고쳐지지 않는 것을 말한다.