동적 메모리 할당 (heap, sbrk, malloc, free)

동적 메모리 할당이라는 주제에서 제목에 적혀 있는 네 가지의 요소는 모두 프로그램 실행 중 메모리를 관리하는 하나의 체계를 구성한다.
이들은 프로세스 메모리 관리 메커니즘이라는 공통 이론으로 연결되어 있다.

힙, 스버륵, 맬록, 프리 이 네 가지 개념은 다음과 같은 계층적 관계로 연결된다:

힙 | 동적 메모리의 근간이 되는 요소이다.

  • 프로세스 메모리의 일부로, 크기가 가변적인 영역이다.
    • [ ] 이 가변성은 어떤 주체의 판단에 따라 변하지? : 가변의 정도는 OS, 메모리 관리 로직, 하드웨어 자원이 협력하여 결정된다.
      • OS 입장에서
        • 가상 메모리 시슽메을 통해 프로세스 별 최대 힙 크기를 설정한다.
        • brk(), sbrk() 시스템 콜을 통한 힙 확장 요청을 처리한다.
        • Page Fault 발생 시 물리 메모리, 스왑 영역과의 매핑 관리를 수행한다.
        • 64비트 시스템에서 이론적 최대 8TB까지 허용한다. 실제로는 메모리 제한이 있겠지만..
      • 메모리 할당자 | malloc 입장에서
        • Free List 관리를 통해 기존 해제 메모리를 재활용한다.
        • 128KB 이상의 대용량 할당 시도는 mmap() 시스템 콜 사용하여 힙 단편화를 방지한다.
        • 두 수준 분할 할당 등의 알고리즘으로 효율적인 블록 관리를 유도한다.
      • 프로그래머의 제어 입장에서..
        • malloc(2048) 와 mmap(NULL, 4096, ..) 같은 할당 방식을 선택한다.
        • 메모리 누수 방지를 위한 명시적 free() 호출한다.
        • 재할당시 realloc()을 통한 기존 블록 크기 조정을 최적화한다.

가변성에 대한 주요 제약조건은 아래 있는 표를 보면 도움이 된다 :

제약 요소 영향 범위
물리 RAM + 스왑 공간 최대 확장 가능 크기
프로세스 주소 공간 (32/64bit) 이론적 상한선 결정
커널 매개변수 (vm.overcommit_ratio) 과할당 정책 제어

 

  • 동적으로 할당된 데이터가 저장되는 메모리 공간이다.

sbrk/brk | 힙 크기 조절을 담당하는 시스템 콜이다.

  • 프로그램의 힙 영역을 조정하는 저수준의 시스템 호출이다.
  • 힙 메모리의 끝을 가리키는 program break을 조정한다.
  • 일반적으로 프로그래머가 직접 호출하지 않고, malloc이 필요하다고 판단될 때 내부에서 사용된다.

malloc | 사용자 수준의 메모리 할당 함수이다.

  • C 라이브러리의 포함되어 있는 코드이다. 동적 메모리 할당을 수행한다.
  • 내부적으로 sbrk을 호출하여, 필요 시 힙 크기를 확장한다.
  • 사용자가 지정한 크기의 메모리를 할당하고 그 주소를 반환한다.
  • 메모리 요청 시 기존에 해제된 메모리 블록을 재사용하거나, 없을 경우 새로운 메모리를 할당한다.

free | 할당 메모리를 가용 메모리로 해제시키는 함수이다.

  • malloc으로 할당된 메모리를 해제하는 함수이다.
  • 해제된 메모리 블록은 리스트에 추가되어 향후 malloc 호출 시 재사용된다.
  • 해제된 블록이 힙의 끝에 위치 할 경우 brk을 호출하여 힙 크기를 축소 시킬 수 있다.

동작 원리, 이 개념들은 다음과 같이 함께 작동한다.

  1. 프로세스가 시작되면 시스템은 코드가 포함된 텍스트 세그먼트, 정적 데이터, 스택 및 힙 영역을 할당한다.
  2. 프로그램이 malloc을 호출하면, 라이브러리는 먼저 기존 해제된 메모리 블록에서 적절한 크기를 찾는다.
  3. 적절한 블록이 없으면 sbrk을 호출하여 힙 크기를 확장한다.
  4. 프로그램이 free를 호출하면, 해당 메모리는 재사용 가능한 블록 목록에 추가된다.
  5. 메모리 블록은 메타 정보와 실제 데이터 영역으로 구성되며, 이중 연결 리스트로 관리된다.

이 시스템을 통해 프로그램은 실행 시간에 필요한 만큼의 메모리를 요청하고 해제 할 수 있다. 이는 컴파일 시간에 메모리 요구 사항을 결정 할 수 없는 프로그램에 필수적이다. 현대 운영체제에서는 이 전통적인 메커니즘 외에도 대용량 메모리 할당을 위해 mmap 같은 다른 시스템 콜을 사용하기도 한다.