유닉스 V4 소스에서 찾은 dmr의 malloc: 명시적 메모리 영역을 받던 잃어버린 할당자
- 1973년 유닉스 V4 소스의 /usr/sys/dmr/malloc.c에서 데니스 리치가 쓴 malloc()과 mfree()를 확인했는데, 두 함수 모두 coremap, swapmap 같은 명시적 메모리 영역 포인터를 첫 인자로 받았고 mfree()는 해제할 객체의 크기까지 넘겨받음
- /usr/c/c20.c의 alloc()은 sbrk(2000)으로 힙을 늘리는 선형 할당자(범프 할당자)로, 공간이 없으면 Out of space를 출력하고 exit(1)로 끝나서 호출자가 NULL을 검사할 필요가 없음
- V4 테이프는 지난해 스토리지 정리 중 발견됐으며(Rob Ricci), 그전까지 완전히 소실된 것으로 여겨졌음
- coremap[CMAPSIZ]와 swapmap[SMAPSIZ]는 systm.h에 선언된 평범한 메모리 배열이고, 처음엔 크기를 CMAPSIZ/2, SMAPSIZ/2로 잡아야 했던 실수가 있었지만 나중에 수정됨
- 존 라이온스의 V6 해설서에 따르면 주기억장치는 32워드(64바이트), 디스크 스왑 영역은 256워드(512바이트) 단위로 관리됐고 이 인터페이스는 V6까지 그대로 유지됨
Hacker News opinions
프론트페이지에 평점 4점짜리 글이 올라온 건 처음 본다. HN 알고리즘은 진짜 미스터리임.
15년 전 대학생 때 A Book on C로 C를 처음 배웠는데, 범프 할당자 같은 게 벌써 시도됐다는 게 놀랍다. 어떻게 선배들은 이런 걸 다 했을까.
그 시절엔 CS가 이론 중심이라 알고리즘 최적화에 관심이 쏠렸고 시스템도 단순해서 근본적인 부분을 실험하기 쉬웠음. 하드웨어에 가까운 코딩이었으니 평균 프로그래머도 내부 구조를 더 잘 알았고. 배우기 쉽고 익히기 어렵다는 말이 딱 맞음.
종이에 먼저 다 써보고 코딩해봐라. 그때는 컴파일 한 번에 몇 시간 걸려서 오타 하나로 기다리는 걸 아무도 원하지 않았음. 요즘 언어도 설계는 종이에서 시작하는 게 리팩터링을 줄여줌.
필요가 발명의 어머니라는 말 그대로임. 똑똑한 사람에 시스템 제약이 더해지면 기발한 게 나옴.
요즘 학생들이 역사를 안 배워서 자기가 새로 발명한 줄 아는 것뿐임. 아리스토텔레스도 헤시오도스도 똑같이 불평했고 아리스토파네스는 그걸 풍자하는 희극까지 썼음.
빈 머리로 접근해서 나온 결과임. 요즘 같은 복잡함이 없는 상태에서 인터넷도 없이 터미널 앞에 앉아 있었다면 누구나 나왔을 것.
글쓴이 주장엔 별로 공감 안 됨. 아레나 할당자에 그렇게 열광하지도 않고 free가 크기를 안 받는 인터페이스도 괜찮다고 봄. 선형 할당자는 메모리를 더 쓰고 단편화도 잘 일으켜서 우리가 서서히 멀어진 거임.
아레나나 선형 할당자는 실시간 시스템에선 진짜 좋음. 커널 안 건드리고 한 번에 리셋할 수 있으니까.
mfree가 크기를 받는 건 업계 역사상 가장 큰 작은 실수 중 하나임. free() 부르는 쪽은 항상 크기를 아는데 그걸 할당자 안에도 똑같이 기록하니 부기가 두 번 일어남.
void* 때문에 예외가 너무 많음. rustc에 TCMalloc 붙여봤다가 세그폴트 났음. 크기는 정확성 요구사항이 아니라 최적화 힌트여야 함.
걱정할 필요 없음. 할당자는 크기를 힙에 거의 저장 안 하고 크기 버킷으로 나눠서 포인터만으로 유추함. 싸고 좋은 전략임.
free()를 더 쓰기 어렵게 만들면 메모리 안전성 버그만 더 늘어남.
size_t 하나 아끼는 건 malloc 자체 오버헤드에 비하면 미미함. 낭비가 신경 쓰이면 초기화할 때 OS에서 페이지를 직접 받아서 아레나를 써라.
C++ 다형성은 어떻게 함? A* blah = new B(); 하면 크기가 다른데.
할당자는 보통 두 개 크기를 유지해야 함. 요청한 객체 크기랑 실제 점유한 메모리 크기. 그래서 free(ptr)만 받는 게 맞는 정의고 할당자한테 자유를 주는 것임.
하위 레이어를 어렵게 만들수록 사람들은 상위로 도망감. 자바는 2배, 스크립트 언어는 100배까지 느려지는데도 그렇게 함.