malloc() 작동 원리

http://blackrain.egloos.com/1224982

글 본문에 대한 내 생각을 밝히는 것이 아니기 때문에 트랙백은 남기지 않았다. 다만 글 쓰신 Gony님이 인용하신 '조엘 온 소프트웨어'의 대목에 많은 오류가 있어서 이렇게 글을 적어본다. 물론 좁은 지면과 독자의 배경 지식을 감안해서 쉽고 간단하게 malloc() 동작 원리를 썼으리라 생각한다. 그러나 실제 방식은 이와 많이 다르다. 혹시나 오해를 가질까 해서 이 글을 쓴다.

malloc이 어떻게 동작하는지 아십니까? malloc의 본질은 사용 가능한 메모리 블록을 연결 리스트linked list로 길게 연결한 자유 체인(free chain)입니다. malloc은 연결리스트를 따라가며, 요청 받은 메모리 양보다 큰 블록을 찾습니다. 이렇게 찾은 블록을 2개로 쪼개서, 하나는 호출한 사용자에게 반환하며, 쪼개고 난 다음에 남아있는 블록은 다시 연결 리스트에 넣어 둡니다. free를 호출할 때, free는 해제한 메모리를 자유 체인에 추가합니다. 결국 자유 체인은 자그마한 조각으로 잘게 쪼개지므로, 큰 조각을 요청하면 원하는 크기를 충족하는 조각이 없을 수도 있습니다. 이럴 경우 malloc이 타임아웃을 선언한 다음에 자유 체인 주위를 샅샅이 훑어 조각을 정렬하고 인접한 작은 자유 블록을 더 큰 블록으로 결합합니다. 이런 작업을 하다 보면 밤이 샐 것입니다. 결국 이 모든 혼란의 끝은 malloc의 성능 특성이 결코 아주 빠르다고 볼 수 없으며(malloc은 항상 자유 체인을 돌아다닙니다), 정리하는 과정에서 종종 예측할 수 없을 정도로 지독하게 느려질 수 있다는 사실로 귀결됩니다.

덧붙여 말하자면, 이런 현상은 가비지 컬렉션을 지원하는 시스템과 동일한 성능 특성이며, 시스템 성능 저하 원인이 가비지 컬렉션(garbage collection)이라는 주장이 전적으로 옳지만은 않다는 놀라운 결론에 도달합니다. 비록 정도는 약하지만, 전형적인 malloc구현을 따를 경우에도 가비지 컬렉션과 유사한 성능저하 문제가 생기니까요.

아 길다. 이걸 직접 타자하신 것 같은 Gony님께 감사의 말씀을 전한다 (띄어쓰기는 손을 좀 봤습니다). malloc의 작동 원리는 보기에는 간단하지만 실제로는 수 많은 최적화가 되어있어서 상당히 복잡하다. malloc 구현은 사실 여러 가지 버전이 있다. 대표적으로 리눅스의 libc에서 사용되는 Doug Lea의 dlmalloc이 있다. 이 외에도 Solaris 플랫폼의 버전도 있고 Win32 Heap 관리 알고리즘도 있다. 약간의 미세한 차이는 있지만 큰 틀은 차이가 없다. 내가 지적하는 것은 모두 Doug Lea의 malloc 구현 (버전 2.8.3)을 바탕으로 이야기 하는 것이다.

malloc구현은 일단 큰 메모리를 시스템으로부터 얻어오는 것으로 시작한다. 리눅스라면 brk/sbrk가 있고, Win32라면 VirtualAlloc이 있다. 이들 함수가 user-level에서 사용할 수 있는 가장 원초적인 메모리 할당 함수들이다. 그러나 이들 메모리 할당 함수들은 그 할당 단위가 크다. 보통 페이지 단위이기 때문에 4KB 정도이다. 그리고 시작 메모리도 이 페이지 크기에 정렬이 되어있어야 하므로, 작은 메모리를 동적으로 할당 받고 쓰기에는 사실 상 불가능하다. 그래서 이렇게 크게 얻어온 메모리 덩어리를 잘게 썰어주고 관리하는 녀석들이 heap management library이다. 그리고 이 malloc 구현은 20년 가까이 된 것이고 속도와 메모리에 상당히 많은 최적화가 되어있다. 속도 보다는 메모리에 보다 더 많은 관심을 기울였다고 볼 수 있다.

또, malloc의 할당 단위는 보통 8byte이고 최소 할당 크기는 16byte 정도 된다. (시스템마다 32/64비트 마다 다를 수 있다). 그러니까 malloc(14)와 malloc(15)를 호출해도 부가 정보를 기록하기 위한 8바이트를 더해 다음 8바이트 단위로 align 시켜서 똑같이 24바이트가 할당 된다.

예를 들어, malloc(16)을 호출해서 100번지의 주소를 반환 받았다면, 92번지에 현재 이 노드가 사용 중인가, 얼마나 할당 하였는가, 혹은 그 전 노드의 크기가 얼마인지를 저장한다. 이러한 노드는 'chunk'라는 구조체로 표현이 되는데 사실 이 보다 더 복잡하다. 비록 8바이트를 metadata를 위해 쓰지만 앞의 chunk가 사용 중이라면 맨 앞 4바이트는 앞 chunk의 데이터로 채워질 수 있다. 그러니까 겹쳐있는 부분이 있다. 메모리를 조금이라도 아끼기 위해 이런 방식을 취했는데 처음 소스 보면 이해하기 쉽지가 않다.

Malloc이 처음 나왔을 당시에는 그 누구도 이걸 악용해서 컴퓨터 제어권을 탈취하는 상황을 생각해 본 사람이 없다. 그래서 보안에는 사실 상 전혀 관심을 두고 있지 않았다. 물론 익히 알려진 consolidation attack등을 막기 위해 몇몇 알고리즘이 바뀌었고, Windows XP SP2에는 metadata 중 security cookie를 넣기도 하였다. 또한, layout obfuscation이라고 랜덤하게 위치를 바꾸어 공격을 어렵게 하는 방법도 채택이 되었다. 그러나 이러한 방식은 복잡도, entropy가 낮아서 결국 무식한 방법, brute-force로 충분히 뚫릴 수가 있다. 8비트 짜리 security cookie가 가지는 경우의 수가 고작 몇 가지 밖에 안되기 때문이다.


그렇다면 직접 조엘이 한 말을 한 문장씩 검증해보자.

malloc이 어떻게 동작하는지 아십니까? malloc의 본질은 사용 가능한 메모리 블록을 연결 리스트 linked list로 길게 연결한 자유 체인 free chain입니다.

사용 가능한 메모리 블록 (free node)을 관리하는 것은 맞다. 그리고 이미 사용중인 메모리 블록은 따로 관리하지 않는다. 단순히 얼마나 많은 메모리가 사용 중인가 (footprint) 정도만 기억할 뿐이고, 실제 heap에 사용 중인 메모리를 확인하려면 일일이 heap을 돌아다니면서 체크해야 한다. 그런데, 이 free node를 절대 우리가 알고 있는 linked-list 형태로 관리하는 것이 아니다. 물론 chunk struct에 forward/backward로 list 스러운 모습이 있지만 결코 linked-list와 같은 형태로 작동되지는 않는다.

malloc은 연결리스트를 따라가며, 요청 받은 메모리 양보다 큰 블록을 찾습니다.

만약 앞 문장에서 독자가 흔히 알고 있는 linked-list를 떠올렸다면 이 대목은 아주 쉽게 이해가 된다. 즉, free node들을 쭉 이은 리스트를 선형 탐색 (혹은 더 똑똑한 탐색을 하던)으로 'first-fit'으로 하는 것으로 이해할 것이다. 그러나 free node는 그냥 무식하게 다 관리가 되는 것이 아니라 그 크기 별로 매우 효율적으로 관리되고 있다. Free node는 먼저, 512 byte보다 작은 경우에는 그 크기 별로 모두 별도로 관리 된다. 물론 이 때는 linked list 형태로 관리가 된다. 즉, 16 byte 짜리 free node 리스트, 24 byte 짜리 free node 리스트, … 이런 식으로 관리한다. 이들 포인터는 smallbins에 저장이 된다. 그래서 만약 512바이트 보다 작은 메모리가 요청 된다면 이 smallbins을 뒤져서 바로 free node 하나를 때어준다. 그러니 탐색을 할 필요 없고 그냥 상수 시간에 요청이 완료 된다.

그리고 이 보다 큰 경우에는 treebins라는 Trie 자료구조를 이용해서 저장이 된다. 그래서 임의의 크기가 들어왔을 때 'best-fit'으로 적합한 free node를 찾는데 결코 시간이 오래 걸리는 작업이 아니다. 트리 같은 구조를 순회를 하기는 하지만 Trie 자료구조 특성상 depth 에 비례하는 time complexity를 가진다. 일반 binary search tree처럼 전체 노드 개수 n과 관계가 없다.

마지막으로 페이지 단위보다 큰 메모리 요청이 들어오면 그냥 바로 mmap이나 VirtualAlloc을 불러버린다. 그래서 크기를 대략 3개의 큰 분류로 나누어서 처리한다. 게다가 비교적 최신 버전 malloc 구현에서는 designated victim이라는 변수를 두어 조금이라도 순회하는 양을 줄이려고 한다.

이렇게 찾은 블록을 2개로 쪼개서, 하나는 호출한 사용자에게 반환하며, 쪼개고 난 다음에 남아있는 블록은 다시 연결 리스트에 넣어 둡니다.

정확한 표현이다. 쓰고 남은 블록은 위에서 설명했듯이 크기가 크다면 treebins으로, 크기가 작다면 바로 리스트에 연결해준다. 그리고 locality를 보존해서 캐쉬 효율성을 높이려는 부분도 엿볼 수 있다.

free를 호출할 때, free는 해제한 메모리를 자유 체인에 추가합니다.

이 말은 맞으나, 단순히 해제한 메모리를 추가하는 것 이외에 coalescing, 즉 병합이라는 과정도 병행한다. 만약 free되는 노드 앞에도 free node라면 그 자리에서 바로 backward-consolidation을 수행한다. 초창기의 heap buffer overflow 어택은 바로 이 과정을 노린 것이었다. 여기에 포인터 연산이 들어가는데, 만약 이 metadata를 엄하게 고쳐놓으면 이상한 곳으로 점프할 수 있었다. 물론 이제는 이렇게 간단하게 heap integrity가 손상 받지는 않는다.

결국 자유 체인은 자그마한 조각으로 잘게 쪼개지므로, 큰 조각을 요청하면 원하는 크기를 충족하는 조각이 없을 수도 있습니다. 이럴 경우 malloc이 타임아웃을 선언한 다음에 자유 체인 주위를 샅샅이 훑어 조각을 정렬하고 인접한 작은 자유 블록을 더 큰 블록으로 결합합니다. 이런 작업을 하다 보면 밤이 샐 것입니다.

첫 번째 문장이야 당연히 맞는 말이지만, 타임아웃 등의 이야기는 전혀 사실이 아니다. 적어도 Doug Lea의 구현에서는 저런 부분을 찾아볼 수가 없다. 위에서도 말했듯이 인접한 작은 자유 블록을 결합하는 것은 free를 할 때 마다 수행을 이미 했다. 그래서 안정된 힙 구조에서 (즉, malloc/free 호출이 끝난 뒤), 인접한 두 블록이 모두다 자유 블록인 경우는 절대 없다. 그래서 자유 체인 주위를 샅샅이 순회해가며 삽질하는 경우가 없다. 무한정 시간이 걸리는 부분은 한 곳도 없다. 그냥 찾다 찾아도 빈 공간이 없으면 (그래 봐야 3~4단계 작업이면 바로 알 수 있음), 그냥 sbrk등을 호출해서 메모리를 늘린다.

만약, 너무 많은 메모리 요구로 힙이 매우 단편화 되어있고, 그리고 최악의 경우가 발생해 매번 자유 블록 보다 큰 메모리가 들어온다고 해도 느려지는 것은 malloc 외적인 요소, 즉 스와핑이나 과도한 페이지 폴트로 인한 것이지 malloc 자체에서 병목현상은 거의 일어나지 않는다고 볼 수 있다. 작은 크기의 malloc/free는 1초당 5백만 번 이상 일어날 수 있을 정도로 상당히 빠르다. 그러나 일반적인 프로그램에서 이런 경우는 매우 찾아보기 힘들다. malloc 때문에 밤샌다는 표현은 비록 과장이지만 너무 터무니 없고 잘못된 인상을 심어주기에 충분하다.

결국 이 모든 혼란의 끝은 malloc의 성능 특성이 결코 아주 빠르다고 볼 수 없으며(malloc은 항상 자유 체인을 돌아다닙니다), 정리하는 과정에서 종종 예측할 수 없을 정도로 지독하게 느려질 수 있다는 사실로 귀결됩니다.

따라서, 이 결론도 완전히 거짓말이다. malloc은 결코 자유 체인을 항상 돌아다니지 않는다. 돌아다니는 것이 아니라 smallbin 뒤지고, treebin 뒤지는 과정만이 있고, 이 과정은 설명하였듯이 O(n)과 같은 시간이 걸리는 것이 아니다. 예측할 수 없을 정도로 느려진다면 이미 이 프로그램 자체가 매우 메모리를 과다하게 쓴다는 그 원초적인 문제 때문이다.

물론, 예전 에서도 잠깐 언급했는데, malloc은 멀티프로세서를 고려하지 않았다. 그래서 false sharing등이 큰 문제로 대두되어 여러 방법이 나오기도 하였다. 또, 최근 심각한 문제인 heap overflow vulnerability를 어떻게 막을 것인가도 여전히 숙제이다.

주절주절 거리다 보니 정말 글이 길어졌다. 과연 여기까지 얼마나 많은 분께서 다 읽으셨는지 궁금하다. 작년 가을 malloc 가지고 사투를 벌리면서 얻은 그래프나 하나 붙여본다. 3DMark 06 이 수행 도중에 얼마나 많은 malloc을 요청하는지 데이터를 뽑아보았다. 스레드 하나가 아니라 여러 개에서 부르다 보니 이 데이터 얻는데 꼬박 하루를 날렸었다. ㅠ 보면 초당 25만 번 까지도 malloc 요청이 일어나는데 이 정도로는 전혀 heap-intensive라고 부르지 않는다. 최소 2백만 번은 불러야 좀 빡센 프로그램으로 분류할 만큼 malloc은 빠르게 돌아간다.


정작 조엘이 언급하고 있는 가비지 콜렉터 이야기는 다음에 한 번… 흔히 자바에는 가비지 콜렉터 덕 분에 memory leak이 없는 것으로 알고 있지만 이는 잘못된 사실이다. 여전히 memory leak이 존재할 수 있다.

by object | 2007/06/02 00:46 | 컴퓨터 | 트랙백(4) | 핑백(3) | 덧글(22)
트랙백 주소 : http://minjang.egloos.com/tb/1232908
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]
Tracked from Xeraph Online at 2007/06/02 01:20

제목 : .NET 1.0의 GC와 커다란 객체
Production Debugging for .NET Framework - Debugging Memory Problems 85K 이상의 커다란 객체를 할당하게 되면 GC 되더라도 해당 메모리 영역은 프로세스가 OS로 반환하지 않는다는군요. 닷넷 1.0 시절 이야기이긴 하지만 메모리 한계까지 가도 반환을 안 했다니 좀 황당하기도 하고.. 그 외의 기억할만한 사실들 (1.0 시절 기준) ADPlus (hang 걸고 덤프 뜨거나 프로세스......more

Tracked from CodeDream.NET at 2007/08/01 16:44

제목 : malloc()의 분석..
malloc() 작동 원리에 대해 좋은 글을 보게 되었네요~생각보다 복잡하게 구현되는 이 malloc()은 "조엘온 소프트웨어"라는 유명한 책에서도 소개가 되어있는데, 제가 지금 소개시켜드릴려고 하는 글은 그 책에서 설명한 malloc에 대한 지적을 담고 있습니다~자 보다 자세한 내용은 아래 링크를 클릭하세요 ^^malloc() 작동 원리크리에이티브 커먼즈 라이센스이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국......more

Tracked from 깜장천사의 이런 저런 .. at 2007/08/27 14:19

제목 : malloc / free 분석
http://minjang.egloos.com/1232908간만에 좋은 글을 읽었습니다. malloc / free에 대한 작동 원리 글입니다.아주 깔끔하게 적어주셔서 팬이 될 것 같은 글이네요. 윈도우에서 고성능 서버프로그램을 짜다 보면 결국 malloc이나 free 자체도 속도가 문제가 되어서 메모리를 미리 나누어 두고 Thread 별로 자체적인 메모리 관리자를 만들어서 처리를 했었습니다. heap object를 충분히 크게 여러 개 ( 되도......more

Tracked from 어린왕자와 여우 at 2008/10/15 17:04

제목 : malloc()의 작동원리
돌아다니다가 아주 멋진 스레드를 찾았다 ㅎㅎmalloc() 작동 원리...more

Linked at art.oriented : M.. at 2007/08/18 16:43

... c는 malloc에 직접적인 구현이 다 들어가있지만 MSVC는 HeapAlloc으로 연결해놓았을 뿐이다. 물론, HeapAlloc/HeapFree의 동작방식도 malloc 동작 방식과 거의 차이가 없다. 다만 Windows XP SP2 이후 부터는 잦은 heap overflow attack을 막기 위해 약간의 보안 기능이 들어갔다 (그러나 ... more

Linked at head님의 이글루 : 잠시 at 2008/06/18 00:01

... http://mwultong.blogspot.com/2007/02/c-malloc.htmlhttp://minjang.egloos.com/1232908 ... more

Linked at Where does this .. at 2010/08/06 09:29

... %9F%B7%E5%A9%A6%E8%91%AC-Asia.html내용 : 이와 관련된 글이 있어 내용을 추가한다.제목 : 'malloc() 작동 원리'출처 : http://minjang.egloos.com/1232908내용 : ... more

Commented by xeraph at 2007/06/02 01:21
오래 전 시스템 프로그래밍 수업 후반에나 조금 들었던 내용들이네요. 잘 읽었습니다 ;)
Commented by object at 2007/06/02 01:42
아직까지 malloc/new한 녀석을 해제하지 않고 프로그램 종료하면 시스템에 영향이 남는 것으로 아시는 분이 계시던데 그렇지 않습니다. 힙은 프로세스에 국한 된 자원이라 프로그램 죽으면 메모리 릭이고 다 없어집니다.

GC가 디텍트 하지 못하는 메모리 릭의 유형은, 해당 객체에 대한 ref는 살아있지만 실제 프로그램에서 더 이상 사용되지 않는 것들이 있을 경우입니다. 이런 경우는 프로그램 semantic을 분석해야하기 때문에 쉽지 않죠. 물론 여러 방법이 제시 되어있습니다. 재밌더군요.
Commented by 극단적인그녀 at 2007/06/02 03:22
좋은 글 잘 읽어보았습니다 : )
Commented by yiaong at 2007/06/02 06:10
아, 많이 배웠습니다. 감사합니다.
('조엘...' 쪽으로 트랙백을 거셔야 하는 게 아닌가 싶은데요. ^^)
Commented by 학주니 at 2007/06/02 12:22
북마크 해뒀습니다. ^^;
차근차근 읽어봐야할 듯 합니다. ^^;
Commented by object at 2007/06/02 12:38
이것도 최대한 간단하게 설명한 것입니다. 실제 구현은 훨씬 복잡해요. Segment도 있고 mspace라는 것도 있고 정말 소스 이해하고 분석하는데 2주 정도 걸렸습니다. 참고로 Doug Lea 구현은 윈도우에서도 아주 잘 돌아갑니다. 거의 손 볼 것 없이 바로 컴파일 하면 잘 돌아갑니다. 그리고 과도한 매크로 및 #ifdef로 소스 보기에도 벅찹니다 -_-;
Commented by Gerald at 2007/06/02 16:27
좋은글 잘 보고 갑니다...감사합니다 ^^ 사실 날림으로 읽었는데... 볼일보고 나서 다시 정독을 해야 겠습니다.
Commented by object at 2007/06/02 16:46
틀린 부분이 있으면 대략 난감; 개쪽 -_-;
Commented by sakuragi at 2007/06/03 01:58
정작 malloc을 쓰면서도 이런 생각은 해본적도 없는데, 좋은 글 잘 보고 갑니다. :D
Commented by Gony at 2007/06/04 14:14
와우~ 잘 보고 갑니다~ 이글을 보니깐 제가 배울게 참 많아보이네요~ ㅎㅎㅎㅎ
Commented by 고어핀드 at 2007/10/12 15:37
와아~ 시스템 프로그래밍 시간에 단순하게 이론만 배웠는데 자세한 과정은 이렇게나 복잡하군요. 제가 전혀 모르던 부분 - 요청하는 메모리 크기에 따라서 전혀 다르게 관리되고 있다는 - 이 흥미로웠습니다. 항상 좋은 글 잘 보고 있습니다. 앞으로도 좋은 글 올려 주시면 좋겠습니다 :D
Commented by ghost at 2007/10/17 03:00
우리랩에 있는 박사과정 학생이 얼마전에 NVIDIA와 전화면접을 했는데
malloc의 동작원리를 말로 설명하는 것이었다고 하네요. 저도 이걸로 공부할께요^^
Commented by 끝과시작 at 2007/11/02 16:25
와우 멋진 글이군요...
회의하다가... 누군가(제가 다니는 회사는 IT계열은 아닙니다.) 메모리할당할 때 malloc같이 느린 거 말고
메모리관리 좀 잘해줬으면 좋겠다고 하니...

메모리관리는 잘 하고 있습니다.
new-delete로 처리합니다.

했는데... 고개를 끄덕끄덕...

제생각엔 malloc이 제일 빠른거 아닌가.. 싶은 생각이 들어서... 웹서핑하다.. 여기까지 왔습니다.
초당 25만번정도까지 malloc요청이 가능하다면, malloc때문에 프로그램이 느려진다는 건..
프로그래밍 디자인에 문제가 있다는 생각이 듭니다.

암튼 좋은 글 읽고 갑니다.
Commented by object at 2007/11/04 03:39
25만번은 완전히 껌이구요. 1백만번도 너끈히 처리합니다. 글에서도 썼듯이 malloc/new가 bottleneck이 아니라 그 전에 많은 메모리를 요구해서 memory footprint가 커지다보니 cache miss도 많이 나고 메모리 스와핑도 해야하고 그런데서 오는 성능저하가 더 큽니다.
Commented by 강환석 at 2008/04/21 14:02
퍼갈게요. 좋은 자료 감사합니다.^^
Commented by yunu at 2008/11/04 21:32
흠 어렵네요..ㅠ.ㅜ 감사합니다.
Commented by jmh at 2009/05/08 17:44
>> 만약, 너무 많은 메모리 요구로 힙이 매우 단편화 되어있고, 그리고 최악의 경우가 발생해 매번 자유 블록 보다 큰 메모리가 들어온다고 해도 느려지는 것은 malloc 외적인 요소, 즉 스와핑이나 과도한 페이지 폴트로 인한 것이지 malloc 자체에서 병목현상은 거의 일어나지 않는다고 볼 수 있다. 작은 크기의 malloc/free는 1초당 5백만 번 이상 일어날 수 있을 정도로 상당히 빠르다. 그러나 일반적인 프로그램에서 이런 경우는 매우 찾아보기 힘들다. malloc 때문에 밤샌다는 표현은 비록 과장이지만 너무 터무니 없고 잘못된 인상을 심어주기에 충분하다.


좋은 글 잘 읽었습니다. 구체적인 구현은 코드를 봐도 이해하기 힘들던데 잘 설명해 주셔서 감사합니다.
다만 윗 부분은 다소 공감이 되지 않는 부분이네요.

glibc의 malloc 구현의 경우 heap 단편화가 많은 편이고 multi thread, multi processor에 대한 고려가 적어서 performance bottleneck이 된다는 자료를 많이 확인하였습니다.

malloc의 잘못된 구현 때문에 힙이 많이 단편화되고 이로 인한 페이지 폴트, 스왑이 발생한다면 malloc이 병목현상의 주범 아닐까요.

제가 알기로 glibc의 malloc이 ptmalloc이고 이 역시 글에서 설명하신 dlmalloc에 기반한 것이라고 알고 있습니다.

일반 프로그램의 경우에도 malloc으로 인한 성능 저하를 찾아보기 쉽습니다. Firefox는 glibc의 malloc을 사용하지 않고 FreeBSD의 jemalloc을 사용하는 것으로 알고 있으며, Webkit의 경우 google의 tcmalloc을 대신 사용하는 것으로 알고 있습니다.

MySQL의 경우에도 이와 유사한 benchmark가 많이 있더군요.

Commented by object at 2009/05/08 21:31
감사합니다. 좋은 지적 감사합니다.

1. 멀티스레드 지원이 약하다는 것은 본문에서도 잘 말하였습니다. 대표적으로 dlmalloc은 전체적으로 락을 하나만 가지고 있어 확장성이 낮습니다. 그리고 false sharing도 매우 큰 문제이고요.

2. 힙 단편화가 많은 것은 '잘못된 구현'으로 보기에는 힘듭니다. 머신 러닝 같은 궁극적인 능동적인 메카니즘을 도입하지 않는 이상 특정 메모리 요구 패턴에 대해서는 힙 단편화가 많이 생길 수가 있습니다. dlmalloc은 그냥 무난하게 쓸 수 있는 범용적인 메모리 할당자이기 때문에 특정 어플리케이션의 독특한 행동에 대해서는 얼마든지 나쁜 성능을 보일 수 있습니다.

3. 동의합니다. 힙이 많이 단편화 되어있고, 즉 locality가 많이 줄어들고 그로 인해 페이지 폴트 등이 빈번히 나오면 그건 malloc의 주범이 맞습니다. 제 표현이 좀 잘못되었네요.

4. 벌써 오래 되어 많이 까먹었는데, dlmalloc의 경우, 힙 단편화를 줄이기위해 그리 많은 테크닉을 사용하지는 않았습니다. 언급했듯이 free를 할 때 앞 뒤 블럭도 free 되어있었다면 병합하는 것 정도. 무엇보다 locality를 크게 고려하지 않고 free list에서 빈 슬랏을 주기 때문에 단편화도 증가할 것 같네요. 검색을 좀 해보니 jemalloc은 단편화를 많이 줄이도록 개선한 것으로 나오네요. Win32에서도 low-fragment heap 모드가 따로 지원되고 있습니다. 분명, 힙 단편화를 줄이려면 그 만큼 시간을 손해보기 때문에 어느 정도 트레이드 오프는 반드시 있을 것으로 생각합니다. 그러니 간단히 말해 늘 dlmalloc이 좋다거나 늘 jemalloc이 좋다고 말 할 수는 없습니다. 이건 뭐 사실 거의 모든 컴퓨터 공학 문제가 그러하죠. tcmalloc은 속도나 스레드 컨텐션을 많이 개선하였네요.

저도 지금 만드는 프로그램이 동적 할당이 매우 중요한데 malloc을 그냥 쓰기에는 힘들어서 이걸 한번 감싸 최대한 메모리 할당/해제 비용을 줄이려고 노력하고 있습니다. 좋은 정보 주셔서 다시 한번 감사드립니다.
Commented by me at 2010/08/06 09:15
동적 할당을 위한 최적의 방법을 찾기 위해 검색을 하다가 이런 좋은 글을 만나게 되었습니다. 좋은 글 감사합니다. ^^

본문과 조금 관련이 있는 기사(?)를 예전에 본 것 같아 저처럼 검색으로 찾아오시는 분들에게 참고가 되지 않을까 라는 생각에 주소를 남겨 봅니다.



출처 : http://www.ednkorea.com/article-78-詭賅葬欽%EF%9B%BD%EF%9F%B7婦葬-Asia.html#
제목 : 메모리 단편화 관리
작성일 : 01 Oct 2004
글 : Jan Lindblad, Enea Embedded Technology
Commented by inlinechan at 2010/11/04 23:44
dlmalloc 의 동작에 대한 글을 검색하다가 귀한 분석을 보고 잘 읽고 갑니다. 그냥 읽고 휙 가려니 도저히 발길이 안 떨어져서 이렇게 글을 간단하게나마 남깁니다. smallbin 의동작은 별 문제가 없어보이나, 그 보다 큰 메모리 할당시에 fragmentation 으로 인한 문제를 해결하고자 하던 차에 기본 동작에 대한 좋은 설명 잘 보고 갑니다.
Commented by at 2011/09/02 20:25
5백만회에 1초라... I750 쿼드코어 2.67MHz 에서 단일쓰레드의 연속 할당/반납은 1백만에 약 60~70 ms 가 나오니, 5백만이면 대략 300ms 정도 나오죠. 그리고 병렬처리 상황에선 약 2~4배 정도 느려지니 대략 5백만에 1초 정도 걸릴듯.

근데 어플리케이션에 따라선 초당 수백만회 할당/반납이 우습게 나오는 경우도 많긴 합니다.
특히 서버의 경우...
그런 경우 malloc 는 확실히 느리죠. 뭣보다 죄다 malloc() 만 쓸 경우 단일 힙에서 할당받다 보니 주소공간 단편화 역시 무시 못할 문제구요.

그런 문제를 신경 쓸만한 고성능 c/c++ 어플이 일반적이 아니라고도 주장할 수 없는게...

요새 일반적인 어플은 죄다 웹 기반으로 이전 추세고, 스탠드얼론 어플이라 쳐도 java, c#, 델파이 같은 언어가 사용되기에 malloc() 이 충분히 빠르니 어쩌니 할 일 자체가 없죠.
게임 역시 이미 구석기 시대부터 실제 구현은 스크립트로 작성됐고, c/c++ 은 엔진 개발에만 사용됐죠.
한국은 좀 특이한 문화가 있어서 예외였지만...

그런 생산성이 중요한 일반적 어플을 c++로 개발한다 쳐도 어차피 그런 어플 개발자들은 malloc() 의 존재 자체를 모르고 로컬변수로 잡을만한 개체조차 ::new 연산자로 할당받으니만큼... 뭐 malloc() 이 빠르니 어쩌니 할 일은 없을듯 합니다.

요즘 c/c++ 의 용도 자체는 속도와 안정성을 책임질 컴포넌트나 미들웨어 개발 등으로 한정되는 추세라...
Commented by 윤광배 at 2011/12/17 02:33
우와.. 좋네요.
태반이 모르는 것 투성인데도
이야기가 흥미로워요.ㅎㅎ

:         :

:

비공개 덧글

<< 이전 페이지 다음 페이지 >>





by 김민장 2008 이글루스 TOP 100
최근 등록된 덧글
개발자 입장에서의 수많은 ..
by Jiyoon at 02/04
저도 아들 돌잔치때 돌잡이 ..
by 박상욱 at 01/18
미국 대학원 원서 작성중에 p..
by 태클사이야 at 01/13
TO: 박PD 로그인 하지 않아..
by 박응용 at 01/10
http://gigglehd.com/zbx..
by dhunter at 12/28
우와.. 좋네요. 태반이 ..
by 윤광배 at 12/17
항상 좋은 글 잘 보고 있습니..
by y2k at 11/23
글이 좋아서 제 블로그에 담..
by 쏭섭 at 11/23
최근 등록된 트랙백
조엘 스폴스키의 강연 (Sta..
by 인덕원칸타타
[Redis] sds.c를 분..
by 조급하지말고 천천히
메뉴릿
이글루 파인더

website counter

Add to Google

rss

skin by 이글루스