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가 더 빠른 방식이다.
MAP_ANONYMOUS 는 solaris10, tru64등에도 있고, solaris9에는 MAP_ANON이라는 이름으로 있네요.
ReplyDelete