ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [C++/OS] 메모리 단편화와 해결 방법은?
    쾌락없는 책임 (공부)/C++ 짜잘이 2022. 8. 28. 21:04
    반응형

    서론

     면접에서 단골 질문들이 몇 있는데 그중 하나가 메모리 단편화와 관련한 이야기였습니다. 타 직군 분들은 어떤 질문을 들을지 잘 모르겠지만 게임 회사들에서는 메모리 단편화와 관련한 질문이 많이 있었습니다. 지금까지 이 질문들에 대해서 대답을 만족스럽게 못한 것 같아 이참에 한번 정리를 해 보려고 합니다. 

     사실 이 글을 OS에서 해야 할까 아님 C++에서 해야 할까 하다가 일단 카테고리는 C++로 넣게 되었습니다. 제가 주로 알아본 게 "C++에서 메모리 단편화"라 이렇게 분류를 한 점 알아주시면 감사하겠습니다.

     

     

    메모리 단편화란

     일단 메모리 단편화에 대해서 알아보겠습니다. 크게 2가지 종류가 있고 "내부 단편화"와 "외부 단편화"가 있습니다.

     

     일단 내부 단편화의 경우 프로세스가 필요한 메모리보다 많은 메모리를 할당한 경우를 의미합니다. 만일 프로세스가 10MB의 크기를 원했는데 100MB를 극단적으로 할당해 줬다면 남은 90MB는 다른 프로세스에서 사용하지 못하고 남은 메모리가 됩니다. 이게 내부 단편화죠.

    10MB ... 10MB 10MB 10MB 10MB 10MB
    프로세스 A (10MB 외 안씀) 프로세스 A 프로세스 B 프로세스 B 프로세스 B 프로세스 C

     이러면 새 프로세스가 들어올 때 프로세스 A 에서 90MB를 남겨먹는데 들어갈 수 없게 됩니다.

     

     

     외부 단편화의 경우 남은 전체 메모리는 충분히 큰데 이것들이 흩어져 있어서 할당이 안 되는 경우를 의미합니다.

    A B 20MB 남음 C C 30MB 남음

    위 상태의 메모리에서 50MB 크기의 프로세스를 넣으려고 하면 들어갈 자리가 없게 됩니다. 이로 인해서 메모리의 성능을 다 끌어올릴 수 없게 됩니다.

     

     

    이를 해결하는 방법은?

    일단 해결하는 방법까지는 여러 래퍼런스들이 많이 있습니다. 일단 OS공부를 하다 보면 나오는 메모리 단편화 해결법들에 대해서 알아보도록 하겠습니다.

     

    외부 단편화 해결법들

     

    1. 페이징 (Paging)

     페이징 기법은 보조 기억장치(디스크, SSD 등)를 메모리처럼 구역을 나눈 뒤 필요한 부분을 메모리로 옮겨서 사용하는 걸 의미합니다. 여기서 Page, 페이지는 프로세스를 일정한 크기로 나눈걸 의미합니다. 

     이 과정에서 첫 페이지를 우선 로드한 뒤 이후 페이지를 차례로 가져오는 방식입니다. 프로세스가 같은 페이지를 사용한다면 이를 함께 사용해 메모리를 절약할 수도 있고 이 페이지에 대한 테이블 (PTBR)이 필요하게 됩니다. 이로 인해 시간, 공간적 오버헤드가 나오게 되는데 시간적 오버헤드는 자주 사용하는 페이지 테이블을 저장하는 버퍼(TLB)를 둬서 해결을 할 수 있습니다.

     

    2. 압축

     비용이 상당히 드는 방법으로 삭제 공간들을 회수하여 메모리를 정리합니다. GC 에서 메모리 재배치에 해당하는 내용입니다.

     

    3. 통합

     압축과 다르게 인접한 것들간 메모리를 통합한다는 점이 다릅니다.

     

     

    내부 단편화 해결

     

    1. 세그멘테이션

     위 페이징이 일정 크기로 나누는 것이라면 세그멘테이션은 논리적인 단위를 의미합니다. 역시 가상 메모리를 사용하고 매핑을 위한 테이블이 따로 필요하게 됩니다. 프로세스가 필요한 만큼만 딱 주기 때문에 내부 단편화는 일어나지 않지만 여전히 외부 단편화는 남아 있게 됩니다.

     

     

    둘 다 해결 가능

     

    메모리 풀

     역시나 가상 메모리 기법을 사용하게 되는데 이 경우 외부, 내부 단편화를 해결할 수 있게 됩니다.

     

     일단 필요한 메모리를 직접 지정해 미리 할당받은 뒤 사용한 뒤 반납하는 기법입니다. 이런 풀링 없이 할당, 비할당을 계속하게 되면 단편화를 만들게 되지만 필요할 때마다 할당받은 메모리 공간을 가져다 쓰고 반납하기에 외부 단편화가 생기지 않게 됩니다. 또한 "필요한"만큼이라고 했기에 내부 단편화도 없게 됩니다.

     

     오브젝트 풀링과 비슷한 느낌이며 할당, 해제가 빈번한 경우 유용하게 사용할 수 있습니다.

     

     

    C++ 에서 해결하는 방법들은 있는가

     근데 이런 기법들은 사실 OS에서 처리한다는 느낌이 강하고 프로그래머 입장에서는 어떻게 메모리 단편화를 해결할지 잘 모르는 게 현실입니다. 이와 관련해서 여러 자료들을 찾아봤는데 몇 가지 쓸만한 답변들을 얻은 거 같아서 한번 적어보겠습니다.

     

    - 할당량이 작을수록 단편화가 많이 발생합니다.

     이 경우 작은 풀을 만들어서 해결할 수 있습니다.

     

    - 전역, 정적 객체에 데이터를 넣으세요

     만능 방법은 아니지만 하나의 방법이 될 수 있습니다. 계속해서 사용하는거라면 스택 영역에 넣어 할당/해제를 피해 메모리 단편화를 피할 수 있게 됩니다.

     

    - std::vector 보다 std::deque가 도움될수도 있다

     vector는 연속적인 메모리 공간을 사용해야 하지만 deque는 흩어져 있어도 동작을 하게 됩니다. 이를 통해서 일부 해결할 수 있게 됩니다. 그 외 vector를 사용한다면 미리 사용할 공간을 reserve 하는 게 좋습니다.

    (단 deque는 vector보다 많은 메모리를 잡아먹게 됩니다.)

     

    - 할당자를 사용하기

     

     

    그런데 이것들을 보면서 생각하는건데 C++ 단에서 크게 정보를 구할 수가 없었습니다. 최근 성능이 많이 좋아지기도 했고 운영체제의 성능 업에 따라서 메모리 단편화에 대한 걱정이 많이 줄어든 게 사실이기에 정보를 많이 구할 수 없었습니다. 추가적으로 이후 할당자에 대해서 더 공부해보고 적절한 답이 구해진다면 한번 적어보도록 하겠습니다.

     

     

    참고 자료

     

    How do C/C++ programmers tackle the memory fragmentation problem?

    Answer (1 of 7): Simple… you write your own allocators. I have worked in computer games for about 25 years and this is now a classic problem. Basically, you allocate a huge chunk of memory when your app launches and then you assign it to pools, along wit

    www.quora.com

     

     

    What is memory fragmentation?

    I've heard the term "memory fragmentation" used a few times in the context of C++ dynamic memory allocation. I've found some questions about how to deal with memory fragmentation, but can't find a

    stackoverflow.com

     

    반응형

    댓글

Designed by Tistory.