Monday, April 28, 2008

Memory, Anonymous Memory Mappings

glibc에서 메모리를 할당할 때는 data segment나 memory mapping을 사용한다. 초기에는 2의 배수로 메모리를 쪼개 놓고 malloc호출시 요청한 size와 비슷한 free 공간을 할당해주는 식으로 동작했는데, 이 경우 실제 할당되는 메모리가 요청되 메모리보다 커서 낭비인 internal fragmentation 이 발생하고, 여러개의 작은 free memory로 쪼개져 있는 경우 공간은 있는데, 할당은 못하는 external fragmentation이 발생하는 문제가 있었다. - 이렇게 할당하던 방식을 buddy memory allocation scheme라고 불렀다(glibc는 이 알고리즘 말고도 arena algorithm이라는 더 발전된 알고리즘도 사용한다).

glibc에서 메모리를 할당할 때 사용하는 heap이 free를 한다고 바로 줄어들지는 않고 할당된 메모리보다 heap이 너무 커진 경우에만 shrink 한다. 그리고 glibc는 큰 메모리 할당의 경우에는 heap을 사용하지 않는다. 일반적으로 요청된 메모리의 크기가 128 KB 이상인 경우 glibc는 anonymous memory mapping을 사용한다(mmap 과 비슷한 식으로 메모리를 커널로 부터 할당받는다). anonymous memory mapping은 아래와 같은 장단점이 있다.

  • fragmentation이 없다.

  • 할당 후 크기조절이 가능하다.

  • heap을 거칠 필요가 없다.



  • 커널의 페이지 사이즈 크기 배수로 할당 받는다(공간 낭비가 있을 수 있다).

  • 새로운 공간을 할당받는 overhead가 heap에거 가져오는 건 보다는 크다


anonymous memory mapping은 직접할 수도 있는데, 아래처럼 mmap을 사용하면 된다.

void *p;

p = mmap(NULL,
512*1024, // size
PROT_READ|PROT|WRITE, // 권한
MAP_ANONYMOUS|MAP_PRIVATE, // anonymous !
-1, // fd 인데, -1안줘도 되긴 함
0); // offset (ignored)

if (p == MAP_FAILED) perror("mmap");


이렇게 할당된 메모리에서 특정 코드를 수행하려 할 수도 있겠으나, 심각한 보안 취약점이 될 수 있으므로, 하지 않는다. 할당된 메모리들은 모두 0으로 초기화 되어 있다(커널에서 이렇게 할당된 메모리들은 copy on write 로 zero filled 하기 때문에 효율적으로 0으로 초기화 된 메모리를 사용할 수 있다.)

다른 unix 시스템들의 경우에는 MAP_ANONYMOUS 같은 flag이 없다. 대신에 mmap시 /dev/zero를 사용한다(이전의 linux에서도 이 방식을 사용하였다). 하지만 이 경우 추가적인 system call을 수반하기 때문에 anonymous memory가 더 빠른 방식이다.

1 comment:

  1. MAP_ANONYMOUS 는 solaris10, tru64등에도 있고, solaris9에는 MAP_ANON이라는 이름으로 있네요.

    ReplyDelete