chunk structure

glibc는 메모리 동적 할당 api를 제공하기 위해 내부적으로 메모리를 chunk 단위로 관리한다


allocated chunk

    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+  
            |             Size of previous chunk, if unallocated (P clear)  |  
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+  
            |             Size of chunk, in bytes                     |A|M|P|  
      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+  
            |             User data starts here...                          .
            .                                                               .
            .             (malloc_usable_size() bytes)                      .
            .                                                               |
nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |             (size of chunk, but used for application data)    |
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |             Size of next chunk, in bytes                |A|0|1|
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • prev_size : 이전 chunk가 free chunk이면 이 영역에는 이전 chunk의 크기가 저장된다. 반대로 할당된 chunk이면 해당 chunk의 user data가 저장된다
  • mchunk_size : 현재 chunk의 크기. 마지막 세 개의 비트(P, A, M)는 flag bit들이다
    • P (PREV_INUSE) : 이전 chunk가 할당되었는지 나타낸다. 특정 chunk가 할당되었는지 확인하려면 그 다음 chunk의 bit 0를 확인하면 된다
    • M (IS_MMAPPED) : 현재 chunk가 system call에 의해 할당되었는지를 나타낸다
    • A (NON_MAIN_ARENA) : main arena에 포함된 chunk이면 0, thread가 할당받은 arena에 포함된 chunk이면 1

free chunk

    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+  
            |             Size of previous chunk, if unallocated (P clear)  |
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    `head:' |             Size of chunk, in bytes                     |A|0|P|
      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |             (fd)Forward pointer to next chunk in list         |
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |             (bk)Back pointer to previous chunk in list        |
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |             Unused space (may be 0 bytes long)                .
            .                                                               .
            .                                                               |
nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    `foot:' |             Size of chunk, in bytes                           |
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |             Size of next chunk, in bytes                |A|0|0|
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • free chunk에만 있는 필드
    • fd(forward pointer) : 같은 bin에서 다음 chunk를 가리킨다
    • bk(backward pointer) : 같은 bin에서 이전 chunk를 가리킨다

Arena

  • 서로 다른 종류의 chunk들을 가리키는 포인터들이 저장된 구조체
  • 각 thread는 메모리를 요청하면 하나의 arena를 할당받는다
  • arena는 main arena와 thread arena 두 종류로 나뉜다
  • main arena는 프로세스 당 한 개 존재한다
  • 새로운 스레드가 메모리를 요청하면 global linked list에서 arena를 하나 할당해준다
  • 새로운 arena가 없고 전체 arena의 개수가 M_ARENA_MAX를 넘지 않았다면 malloc은 arena를 하나 새로 생성한다

Heap

  • heap은 하나의 frame header와 chunk들로 구성되어 있다
  • Glibc는 OS로부터 메모리를 heap 단위로 요청하고 반환한다
    • glibc에서 heap은 프로세스 메모리 공간 중 heap영역과는 다른 의미이다
    • glibc에서 사용하는 논리적 단위이다
    • glibc는 OS에게 메모리를 요청/반환할 때 heap이라는 큰 단위로 메모리를 요청하고 반환한다
  • main arena와 heap arena는 생성될 때 heap을 하나 가진다
  • thread arena의 heap 크기가 특정 값(64MB) 이상이 되면 새로운 heap이 추가된다
  • heap들은 연결 리스트로 관리된다
  • heap이 처음 생성되면 heap에는 top chunk라는 chunk 하나만 존재한다. 이 heap으로 메모리 요청이 올 때마다 top chunk에서 chunk 하나를 분리한다

references