malloc(16) 1000번에 brk는 2번, glibc가 syscall보다 22.7배 빠른 이유
- malloc(16)을 1000번 불러도 strace에 잡히는 brk syscall은 2번뿐이고, 첫 호출에서 program break를 확인한 뒤 힙을 132KiB 늘리며 나머지 999번은 그 메모리에서 잘라 씀
- 빈 syscall이 575.2ns, sbrk(16)이 610.1ns, malloc(16)이 26.9ns로 malloc이 sbrk보다 22.7배 빠름. 커널에 큰 블록을 한 번에 요청하고 유저스페이스에서 쪼개는 이유임
- 청크마다 반환 포인터 바로 앞에 8바이트 크기 헤더가 붙고, 크기는 요청량에 8을 더해 16의 배수로 올림하며 최소 32바이트임. 16의 배수라 남는 하위 3비트에는 A/M/P 플래그를 넣음
- 주소 공간은 text, data, bss, 힙, libc, 스택 순으로 올라가고 이 실행에서 break와 libc는 23.4TiB 떨어져 있음. 램 15.6GiB의 1,530배지만 대부분 unmapped라 물리 메모리는 안 씀
- 저자가 만든 bump allocator는 요청마다 break를 옮겨 syscall을 부르고 해제한 메모리를 재사용하지 못함. free한 자리 대신 힙 끝에 새로 할당되는 모습을 예제로 보여줌
Hacker News 의견들
malloc 추상화의 복잡도랑 오버헤드 때문에 stack-only 언어인 Goose에 꽂혔음. 힙 할당을 거의 없앨 수 있다는 발상이 매력적이더라.
스택도 결국 bump allocator임. stack-only 언어에서 특별한 건 할당 방식이 아니라 수명 관리 쪽이고.
Zig가 딱 이래서 좋음. allocator를 명시적으로 고르게 만드는 게 코딩 습관을 잡아줌. 힙을 완전히 버리는 건 비현실적이지만 작업에 맞는 할당 방식을 고르는 건 충분히 가능함.
힙을 아예 안 쓰는 게 목표가 아님. 필요한 만큼 미리 크게 잡아서 오래 쓰는 게 핵심임.
malloc 오버헤드가 크다고 읽었으면 glibc malloc이 글쓴이 구현보다 20~150배 빠르다는 대목을 봐야 함. 이 글은 학부 시스템 프로그래밍 수업 수준이고, 실제 allocator는 잦은 작은 할당을 훨씬 싸게 처리함.
Goose 스택도 만만치 않음. 메모리를 미리 왕창 잡고, 컴파일러가 코드를 스택에 맞춰야 하고, 중첩 가변 타입은 만들기 어려움. 결국 linked list 예제도 노드용 풀 allocator를 만듦.
예전에 본 sploitfun의 glibc malloc internals 글이 설명 잘 되어 있음. 찾아보면 좋음.
C는 로우레벨이 아님. malloc 소스를 읽는다고 메모리 할당 원리를 다 배우는 건 printf를 읽고 화면 출력 원리를 배우는 것과 같음. 진짜 마법은 커널에 있음.
malloc이 커널에서 메모리를 받아오는 건 맞지만 제대로 된 구현은 대부분 유저스페이스에서 놀아남. 그 부분을 뜯어보면 배우는 게 많음.
반대임. brk()를 알게 되는 게 커널로 넘어가는 좋은 디딤돌이고, mimalloc만 봐도 유저스페이스 설계 여지가 얼마나 큰지 보임. 커널 자체 page allocator는 freelist나 buddy로 단순한 편이고 slab allocator 논문도 12페이지임.
준비해서 올린 글에 컴파일 안 되는 코드 조각이 있는 건 거슬림. #include <stdlib.h>랑 return 0만 넣어도 되는 건데, GitHub 링크도 깨져 있었음.
난 C에서 동적 메모리를 평생 두 번 썼음. 정적 할당이랑 버퍼, 언롤 루프로 다 해결해서 메모리 누수나 크래시를 겪어본 적이 없음.
wasm에 clang 지원이 막 생겼을 때 libc랑 malloc을 직접 써봤음. free list 같은 걸 배우기 좋았고 .wat로 바로 읽을 수 있어서 좋더라.
malloc은 느림. free까지 쓰면 더 느려짐. 가능하면 배열 하나 잡아서 거기서 잘라 쓰는 게 낫다.
현대 allocator 구조를 보고 싶으면 mimalloc 추천. 코드가 읽을 만하고 brk/sbrk도 없고 boundary tag나 splitting/merging도 안 씀.
cs61 자료가 이 주제 학습에 좋음. malloc 말고 관련된 것도 같이 다룸.