malloc의 원리에 대해 간단히 포스팅했는데 잘못된 있는지 확인해주실 수 있을까요?

wonderer의 이미지

우선 리눅스에 대한 깊은 내용의 포스팅은 아니고 C/C++ 포스팅에 malloc과 new의 차이와 동작 원리에 대한 포스팅입니다.
그래서 완전히 자세하게는 공부하진 않았습니다.(사실 어려워서..)
그래도 꽤 많이 알아보고 작성했습니다 ㅜㅜ 내용은 많지 않은데 혹시나 잘못 이해한 부분이 있을까요?

..................... 시작

malloc이 내부적으로 어떻게 메모리를 가져오는지 알아보자. 운영체제마다 malloc의 동작이 다를 수 있는데 다음의 내용들은 리눅스 기준이라 윈도우즈도 정확히 이렇다곤 못하겠다. 다만 원리 자체는 비슷할 것이라 생각한다.

우선 메모리에 직접적으로 관여하는 것은 운영체제(커널)의 영역이라는 것을 알아야한다. user-level에서 사용하는 메모리 할당은 결국은 커널 수준에서 제공하는 시스템 호출(system call)을 통하여 시스템 메모리를 받아온다. 시스템 호출을 통해 시스템의 자원을 받아올 수 있는 함수로는 리눅스의 brk/sbrk 또는 윈도우즈의 VirtualAlloc이 있는데, 이들은 최소로 할당해줄 수 있는 크기가 페이지(page) 단위로 매우 크기 때문에 malloc 처럼 사용할 수 없고 다른 용도로 사용된다.

어찌됐든 C 언어에서 우리는 결국 malloc을 통해 메모리를 할당하는데, malloc은 사실 항상 시스템 호출을 통해 메모리를 할당해주진 않는다. 보통 malloc은 미리 할당된 메모리 풀(memory pool)을 사용하며, 위에서 소개한 함수들이 만들어준다. 즉 프로그램이 메모리에 로드되면 brk, VirtualAlloc와 같은 시스템 호출 함수를 통해 메모리 풀을 사용자 영역에 만들어준다. 그리고 malloc은 여기서 메모리를 할당 해준다.

윈도우즈에선 이 pool을 프로세스 기본 힙(process defalut heap)이라고 부르는 것 같다. 프로세스 기본 힙이란 프로그램이 메모리에 로드되어 프로세스가 만들어지면 OS가 프로세스 별로 할당해주는 힙 영역인데 리눅스와 비슷해보인다.

메모리 풀(정확한 명칭은 아님)은 heap manager에 의해 관리되는데 brk로부터 할당받은 큰 메모리 블럭을 또 크기 별로 나누어 관리한다. 메모리 크기가 작은 블럭은 small bin에, 크기가 크다면 large bin이라는 곳으로 분류된다. (단위는 검색해보면 나온다.) 힙 매니저는 best-fit 방식으로 malloc이 요청한 메모리를 할당한다. best-fit이란 요청받은 메모리 블럭과 최대한 비슷한 크기의 메모리를 찾아 할당해주는 방식이다.

사용자가 요청한 크기가 작다면 small bin에서, 크다면 large bin에서 메모리 블럭을 찾아 반환해주는데, 만약 반환하는 블럭의 크기가 필요한 크기보다 크다면 블럭을 쪼개서 반환하고 남은 블럭은 다시 원래 메모리에 병합한다. 만약 large bin으로도 감당할 수 없는 크기라면, 그제서야 page 단위로 메모리를 반환하는 mmap과 brk 또는 VirtualAlloc을 호출하여 시스템 자원을 가져다 준다.

Yi Soo An@Google의 이미지

윈도우쪽은 모르겠는데 나머지는 얼추 맞는 얘깁니다.

---------------
Happy Hacking!

wonderer의 이미지

감사합니다! 문맥이 좀 어색한 부분들이 있어서 고쳐야겠네요

황병희의 이미지

wonderer//
열흘전 malloc 으로 뭔가를 하다가 실패했었는데,,,
이렇게 또 깊이있는 도움글 써주셔서 감사드려요^^^

[우분투 18.04 파여폭스 나비에서 적었어요~]

--
^고맙습니다 감사합니다_^))//

Necromancer의 이미지

리눅스에서 메모리 할당 해제하는 시스템콜은 2가지 입니다.

1) mmap(), munmap() : 지정한 파일을 메모리 특정주소로 mapping 하는 함수. 단순 할당용으로 사용시에는 /dev/zero로 mapping하거나 리눅스 한정으로 MAP_ANONYMOUS 옵션 사용.
2) brk(), sbrk() - 실행코드(text)의 끝지점을 변경. 할당시는 늘리고 해제시는 줄임.

malloc()은 이들을 적당히 혼합해서 쓴다고 보시면 됩니다.

malloc()이 호출되면, 프로그램에서는 free()로 반환했지만 아직 시스템에 반환하지 않은 요청 크기보다 큰 블록이 있을 경우 여기서 먼저 빼고, 만일 없을 경우 할당 요청하는데 큰 블록일경우 mmap(), 작은 블록일경우 brk() 쓴다고 보시면 됩니다.
mmap()의 경우 할당 단위가 페이지(CPU 아키텍쳐마다 다른데 x86의 경우 4Kbytes 입니다)라서 직접 쓰기에는 매우 불편합니다.

윈도우는 윈도우 개발자들의 바이블인 win32api 책 보면 있습니다. 주소 매핑 함수인데 기억이 안나네요. 물론 리눅스와 마찬가지로 이들 시스템콜에서 메모리 할당시 할당단위는 mmap()과 마찬가지로 페이지이고, mmap()처럼 파일 내용을 메모리 주소 특정지점으로 매핑하는 기능은 없습니다.

Written By the Black Knight of Destruction

서지훈의 이미지

좋은 글이네요 ㅎㅎ

#include <com.h> <C2H5OH.h> <woman.h>
do { if (com) hacking(); if (money) drinking(); if (women) loving(); } while (1);