메모리 단편화

  • RAM에서 메모리의 공간이 작은 조각으로 나뉘어져 사용가능한 메모리가 충분히 존재하지만 할당(사용)이 불가능한 상태를 보고 메모리 단편화가 발생했다고 한다.

단편화의 종류

  1. 내부 단편화(Internal Fragmentation)
    - 메모리를 할당할 때 프로세스가 필요한 양보다 더 큰 메모리가 할당되어서 프로세스에서 사용하는 메모리 공간이 낭비 되는 상황

  2. 외부 단편화(External Fragmentation)
    - 메모리가 할당되고 해제되는 작업이 반복될 때 작은 메모리가 중간중간 존재하게 된다. 이 때 중간중간에 생긴 사용하지 않는 메모리가 많이 존재해서 총 메모리 공간은 충분하지만 실제로 할당할 수 없는 상황

메모리 파편화 문제 해결 방법

1. 페이징(Paging) 기법 (가상메모리사용, 외부 단편화 해결, 내부 단편화 존재)

  • 논리(가상) 메모리는 페이지(Page)이라 불리는 고정 크기의 블록으로 나누어지고, 물리 메모리는 프레임(Frame)라 불리는 페이지과 같은 크기의 블록들로 나누어짐. 보조 메모리 역시 프레임과 같은 크기의 블록들로 나누어짐.
  • 사용자는 하나의 주소를 지정(하드웨어의 의해 페이지 번호와 변위로 분할)
  • 가상메모리를 같은 크기의 단위로 분할
  • 페이지 테이블에는 각 페이지 번호와 그에 해당하는 프레임의 시작 물리 주소를 저장
  • 할당은 항상 프레임의 정수 배로 할당되는데, 이 때 프로세스가 페이지 경계와 일치하지 않는 크기의 메모리를 요구하게 되면 마지막 페이지 프레임은 전부 사용되지 않고 남아버리는 문제가 발생한다.(내부 단편화)
  • 페이징 기법을 사용하면 연속적이지 않은 공간도 활용할 수 있기 때문에 외부 단편화 문제를 해결할 수 있으나, 페이지 단위에 알맞게 꽉채워 쓰는게 아니므로 내부 단편화 문제는 여전히 있다.
  • 페이지 단위를 작게하면 내부 단편화 문제도 해결할 수 있겠지만 대신 page mapping 과정이 많아지므로 오히려 효율이 떨어질 수 있다.
2. 세그멘테이션(Segmentation) 기법(가상메모리사용, 내부 단편화 해결, 외부 단편화 존재)
  • 세그먼트들의 크기가 다르기 때문에 미리 분할해 둘 수 없고 메모리에 적재될 때 빈 공간을 찾아 할당하는 기법이다.
  • 가상메모리를 서로 크기가 다른 논리적 단위인 세그먼트로 분할해서 메모리를 할당하여 실제 메모리 주소로 변환을 하게 된다.
  • 페이징에서처럼 논리 메모리와 물리 메모리를 같은 크기의 블록이 아닌, 서로 다른 크기의 논리적 단위인 세그먼트(Segment)로 분할
  • 사용자가 두 개의 주소로 지정(세그먼트 번호 + 변위)
  • 세그먼트 테이블에는 각 세그먼트의 기준(세그먼트의 시작 물리 주소)과 한계(세그먼트의 길이)를 저장 * 각 세그먼트는 연속적인 공간에 저장되어 있다.
  • 서로 다른 크기의 세그먼트들이 메모리에 적재되고 제거되는 일이 반복되다 보면, 자유 공간들이 많은 수의 작은 조각들로 나누어져 못 쓰게 될 수도 있다.(외부 단편화)
  • 프로세스가 필요한 메모리 만큼 할당해주기 때문에 내부단편화는 일어나지 않으나 여전히 중간에 프로세스가 메모리를 해제하면 생기는 구멍, 즉 [외부 단편화] 문제는 여전히 존재한다.

3. 메모리 풀(Memory Pool) 

  • 필요한 메모리 공간을 필요한 크기, 개수 만큼 사용자가 직접 지정하여 미리 할당받아 놓고 필요할 때마다 사용하고 반납하는 기법
  • 메모리 풀 없이 동적할당과 해제를 반복하면 메모리의 랜덤한(실제로는 알고리즘에 의한) 위치에 할당과 해제가 반복되면서 단편화를 일으킬 수 있겠지만 미리 공간을 할당해놓고 가져다 쓰고 반납하기 때문에 할당과 해제로 인한 외부 단편화가 발생하지 않는다.
  • 또한 필요한 크기만큼 할당을 해놓기 때문에 내부 단편화 또한 생기지 않는다.
  • 하지만 메모리 단편화로 인한 메모리 낭비량보다 메모리 풀을 만들었지만 쓰지 않았을 때 메모리 양이 커질 경우 사용하지 않아야 한다.
  • 메모리의 할당, 해제가 잦은 경우에 메모리 풀을 쓰면 효과적이다.
  • 미리 할당해놓고 사용하지 않는 순간에도 계속 할당해놓으므로 메모리 누수가 있는 방식이다.

메모리 풀(Memory Pool) 구현

  • 큰 메모리 블록(페이지)을 힙으로 부터 할당
  • 할당 받은 페이지를 각 객체의 크기의 블록으로 나눔
  • 각 객체를 위한 블록을 순차적으로 링크
  • 이 때 현 시점에서 할당할 블록을 특정 포인터가 가리키게 함
  • 메모리 요청이 생기면 현재 헤더 포인터가 가리키는 블록을 돌려준다.
  • 할당이 일어난 후 헤더 포인터는 할당 직전에 가리키던 블록이 가리키던 블록을 가리킨다.
  • 사용되던 메모리가 해제되어 메모리 풀로 돌아올 경우 헤더 포인터는 그 블록을 가리키고 방금 전까지 헤더 포인터가 가리키던 블록을 돌아온 블록의 다음 포인터가 가리키게 한다.

+ Recent posts