힙 영역은 컴퓨터 내의 비어 있는 임의의 메모리 영역이 될 수 있습니다. 스택 영역이 프로그램 시작 시에 정해짐에 반해, 힙 영역은 런 타임에 프로그램이 OS에 요청하여 할당됩니다. 힙 영역은 할당 시마다 반드시 연속되어 할당되는 것이 아니기 때문에 할당 순서에 상관없이 해제할 수 있습니다.
프로그램 실행시 메모리가 할당되는 것을 동적할당이라고 합니다. 그리고 이 때 사용되는 메모리를 개념적으로 heap이라고 하는 것이고요. 그리고 동적할당된 메모리가 3개라면 그 3개를 모두 해제해주어야 합니다. 만약 하나라도 덜 해제해준다면, 메모리 누수라 하여 메모리가 회수되지 않을 경우가 생깁니다. 운영체제에 따라서는 자동으로 해제되기도 하는데, 운영체제가 해제해주기를 바라고 동적할당된 메모리를 해제해주지 않는 프로그램은 그 메모리의 회수가 운영체제에 종속적이기 때문에 좋은 프로그램이라고 할 수 없죠. 만약 운영체제가 메모리를 회수하지 않는 경우가 생긴다면, 정말로 메모리 누수가 발생하게 됩니다. 메모리 누수라 함은 메모리가 회수되지 않는 것을 의미합니다. 즉 메모리를 제대로 회수하지 않는 프로그램은 플랫폼에 종속적인 프로그램이 돼버립니다.
프로그램 실행시 메모리가 할당되는 것을 동적할당이라고 합니다. 그리고 이 때 사용되는 메모리를 개념적으로 heap이라고 하는 것이고요. 그리고 동적할당된 메모리가 3개라면 그 3개를 모두 해제해주어야 합니다.
맞습니다. heap이 뭔지 아는 말은 아니지만.
Quote:
만약 하나라도 덜 해제해준다면, 메모리 누수라 하여 메모리가 회수되지 않을 경우가 생깁니다.
(프로그램의 버그 등으로) 메모리가 회수되지 않는 현상 그 자체를 메모리 누수라 합니다.
Quote:
운영체제에 따라서는 자동으로 해제되기도 하는데,
리눅스, 윈도우 등의 통상적 운영체제들은 프로세스가 종료할 때 해당 프로세스가 사용하던 메모리 공간 전체를 회수합니다. 그러나 이 "회수"와, 프로그램이 제가 가진 힙에서 동적으로 할당한 메모리를 "회수"하는 것은 글자만 같을 뿐 전혀 다른 것을 의미합니다. 추상적 층위에서 추론하지 마세요. 즉 상상하지 마세요. 그건 학습과 practice를 대신한 게으름일 뿐입니다. 그 상상의 결과를 질문과 관계없는 답으로 다는 행동은 어떻게 보아도 좋게 볼 수 없군요.
Quote:
운영체제가 해제해주기를 바라고 동적할당된 메모리를 해제해주지 않는 프로그램은 그 메모리의 회수가 운영체제에 종속적이기 때문에 좋은 프로그램이라고 할 수 없죠. 만약 운영체제가 메모리를 회수하지 않는 경우가 생긴다면, 정말로 메모리 누수가 발생하게 됩니다. 즉 메모리를 제대로 회수하지 않는 프로그램은 플랫폼에 종속적인 프로그램이 돼버립니다.
아직도 종속이 뭔지 개념이 안 잡히나. x라는 변인에 의해 변하는 y를 종속적이라고 합니다. 소멸자 처리를 하지 않았을 때 플랫폼에 따라 메모리 누수가 생길 수도 있고 아닐 수도 있으니 플랫폼이라는 변인에 따라 메모리 누수라는 변인은 종속적이라고 할 수 있습니다. 그래서 종속이라 할 수 있다. 좀 종속에 대한 개념이 뭔지 공부를 하시라니까. 그리고 저 포인터 접근에 대한 것은 님이 아는 이상으로 나도 압니다.
익명 뒤에 숨어서 함부로 말하기 때문이죠라고 그쪽이 말씀했지만, 그렇지 않아요. 님이 남을 무시하는 어조로 말씀하셨지. 본인이 한 일을 기억못하는 까마귀이시군요.
님 의 quote> 첫번째, 제 짐작이긴 하나 님은 이미 한 번 제가 도발하는 말에 정말로 상처 받았습니다. 더 이상은 서로 위험하고요.
라고 말씀하셨는데. 천만에요. 상처 전혀 안 받았습니다. 님은 답변 달지 말라는 말에도 계속 답변만 달더군요. 님은 타자(나)에게 인정받고 싶은거에요. 그게 당신의 문제입니다. 싫으면 그냥 답변 달지 않으면 돼요. 당신한테 답변 달아달란 말 하지 않았으니. 본인이 상처 받아놓고 자신이 받은 상처 받은만큼 상대방이 상처받았으면 하는 너의 마음 상태가 문제인거에요. 아셨죠?
님의 quote> 둘째, 제가 님께 달아드린 gdb 답변 중에 틀린 게 하나 있습니다. 달고 나서도 긴가 민가 해서 확인했더니 틀려서 아차 싶었는데, 님 성격에 그냥 이죽대기만 하고 넘어가시더군요. 찾아보지도 않았다는 거죠.
마치 본인의 실수가 남의 실수인양 몰아붙이고 있죠? 그게 당신의 문제입니다. 님의 실수는 너의 실수로 끝나야죠. 그게 내 실수는 아니죠. 그리고 이죽대기 누가 이죽댑니까? 당신이 깐죽댄 적은 있어도.
님의 quote> 셋째, 저는 님이 "잠시 착각"하신 걸 세 번 지적했습니다.
님이 세 번 지적했는지 알 거 없어요. 님 같은 사람한테 물어본 것도 아닌데. 그리고 익명이 어디 한 둘인가? 님이 몇 번 지적한 것을 내가 기억할 수도 없을 뿐더러 기억할 필요도 없습니다.
여하튼 님의 문제를 남한테 떠넘기지 마세요. 사회에서 깨지기 쉬운 유형입니다. 가차없이 떼거리로 말입니다.
네, 맞습니다. 구체적으로 들어가지 못해 문제인 사람에게 벽만 더 높이는 이에게 한마디 했다가, 첨엔 뭐 이런 게 다 있지? 싶었지만, 뭐 옛날 생각도 나고 ㅎㅎ 역시 내 방식이 맞다는 걸 확인해보고 싶었습니다. 좀 더 나아가보지 못한 건 아쉽지만, 이 정도로 만족합니다.
http://kldp.org/node/142690
위 링크는 제가 나름대로 힙 메모리 영역을 구현한 것입니다.
(자료구조상의 힙이 아니라는 것은 인정합니다.)
처음에는 이걸 참고로 하면 힙을 이해하는 데 도움을 드릴 수 있을 것 같다는 생각을 했지만,
덧글들을 보니 문득 저도 제 맘대로 상상한 결과를 진짜라고 말해버릴 수 있겠다는 생각을 했습니다.
답변이 아니지만, 이걸 가지고 얘기를 나눠보면 저처럼 잘 모르는 사람들이 더 올바르게 힙을 이해할 수 있지 않을까 합니다.
void hd_free(void *ptr) {
char *mp = (char *)ptr - sizeof(int); // 포인터가 가리키는 위치 이전에 할당한 메모리의 크기를 기록합니다.
int offset = *(int *)mp; // 다음 메모리까지의 위치를 저장하는 값이라 이름을 offset으로 했습니다. (offset == memory_size + sizeof(int))
if (offset > 0) // 메모리가 할당되어있다면
*(int *)mp = -offset; // offset 값을 음수로 바꿔 할당을 해제한 것처럼 만듭니다.
}
기본적으로 운영체제 책에 힙 영역 구현이 나와 있습니다. 힙영역 자체는 일정한 메모리 영역에 불과합니다. 기본적으로 정확한 이해를 위해서는 메모리 계층구조에 대한 이해가 선행해야 하나, 간단하게만 설명해 드리겠습니다. 일단 user레벨(사용자의 프로그램)에서 malloc이나 new같은걸로 메모리 요청을 하면, 운영체제는 메모리 블록(4kb정도 단위)를 그 프로그램에 할당합니다. 그리고 그 영역중에 프로그램이 요청한 크기에 맞는 메모리 주소를 돌려줍니다. 그러면 다음번 요청에는 메모리 블록에 아직 사용가능한 영역이 좀 남았다면, 그 부분에서 할당해주고, 부족하다면 메모리 블록을 계속 늘려서 할당합니다. 그리고 이건 가상메모리상의 개념이기 때문에 실제로 하드웨어적인 메모리에 올라가는것이랑은 별 상관이 없습니다. 이런 방식때문에 메모리를 큰 객체와 작은 객체에 번갈아서 할당하게 되면, 프로그램에 사용한 메모리보다 최대 2배에 달하는 메모리가 할당됩니다.
여기서 운영체제는 메모리 블락 내부에 다음번에 할당할 메모리 영역을 계속해서 추적해야 합니다. 대부분의 운영체제는 linked list로 이 구조를 유지합니다. 이때 메모리 요청이 들어오면, list를 따라가면서 현재 요청된 크기의 메모리가 남아있는 블록까지 가서 그 주소를 돌려주고, 없다면 새로운 메모리 블록을 할당하는 겁니다.
메모리 블록 할당은 기본적으로 가상메모리의 기본적인 단위자, 실제 하드웨어 메모리와 cpu 캐쉬에 들어가는 기본단위기 때문에, 실제 하드웨어에 매핑되는 정보도 있어야 할겁니다. 이걸 프로세스의 page table에 기록해 둡니다. 그리고 캐쉬영역에 관한 정보를 CPU의 TLB에 기록합니다.
더욱 자세한 내용에 대해서는 OS책에 대부분 잘 설명되어 있고요, pintos manual과 소스를 보면, 어느정도 운영체제의 메모리 할당의 기본적인 구현에 대해서 보실 수 있습니다.
Linux 같은 일반적인 운영체제를 기준으로 얘기하자면, malloc이나 new 같은 메모리 요청은 운영체제가 아니라 런타임 라이브러리에서 (Linux라면 glibc, libstdc++ 등등) 처리합니다. 여기서 기존에 할당받은 메모리 페이지 중 빈 공간이 있나 찾아보고, 있으면 그 부분을 할당해서 caller에게 돌려주고, 없을 때만 system call을 불러서 운영체제에 추가 메모리를 요청하게 됩니다.
따라서 운영체제는 이 프로그램이 어떤 메모리 주소를 사용중인지 페이지 단위로만 (일반적으로 4K) 정보를 갖고 있으며, 각각의 4K 중에서 어떤 부분이 현재 malloc/new 등으로 사용중인 부분이고 어디가 free된 부분인지는 런타임 라이브러리가 관리하는 부분이고 운영체제는 전혀 신경쓰지 않습니다.
그러니까 위의 글에서
> 이때 메모리 요청이 들어오면, list를 따라가면서 현재 요청된 크기의 메모리가 남아있는 블록까지 가서 그 주소를 돌려주고, ...
이 부분은 OS의 역할이 아닙니다. 기존의 페이지에 충분한 공간이 없어서 새로운 페이지를 할당하는 경우에만 OS가 불리게 됩니다.
이렇게 하는 주된 이유는 malloc이나 new는 굉장히 자주 불리기 때문에 그때마다 운영체제를 부르면 성능이 심각히 저하되기 때문입니다.
1. 동적 할당이 세 번 일어나고 두 번째 것이 해제된다면.
당연히 p1, p3는 남아있고 p2는 해제됩니다. 다만 free 함수의 원형은 void free(void *p)로 인자로 넘긴 포인터 변수 자체의 값을 바꾸는 용도로 사용하지는 않습니다.
이 경우 p2를 인자로 넘긴다고 p2의 값(p2가 가리키는 값을 말하는 게 아닙니다)이 바뀌는 것은 아닙니다. call by value인데 당연하지요?
2. 아래는 사견입니다.
저는 예전에 힙에서 메모리를 해제하면 이전에 할당되었던 메모리를 당기던지 해서 빈 공간을 없앨 것이라 생각했는데,
메모리를 해제한다고 이전에 할당된 메모리를 옮겨버리면 이미 할당된 메모리를 가리키는 변수들은 쓰레기 값을 가리키게 됩니다.
(free 함수에 이전에 할당된 메모리를 가리키는 변수의 주솟값을 전달한다면 모를까..)
결론은 메모리를 해제한다고 이전에 할당된 메모리를 옮기지는 않는다는 뜻입니다. 위에 올린 '제가 만든 Heap'은 이러한 점을 고려해서
메모리 해제는 메모리 해제대로 수행하고, 할당은 hptr이라는 정적 변수를 통해 수행하고 있습니다.
이후에 메모리가 가득 차면 처음부터 탐색해서 빈 공간이 있을 때 할당하려는 것이죠.
이상입니다. 사견이라고 한 건 실제 Heap이 이렇게 동작한다는 문서를 본 적이 없고 제가 생각해낸 것이기 때문입니다.
ps. code 태그를 이용해 코드를 올리면 그 다음 문단부터 글이 자꾸 깨지는데 저만 이런가요?
IE 8, FIrefox 10, 30에서 모두 이렇습니다. 입력 형식을 바꿔봐도 계속 그러네요.
원래 참고용 코드를 작성했다가 글이 자꾸 깨지는 바람에 관뒀습니다.
보통은 링크드 리스트나 RB트리로 메모리를
보통은 링크드 리스트나 RB트리로 메모리를 관리합니다.
http://g.oswego.edu/dl/html/malloc.html 를 참고하세요.
힙 영역은 컴퓨터 내의 비어 있는 임의의 메모리
힙 영역은 컴퓨터 내의 비어 있는 임의의 메모리 영역이 될 수 있습니다. 스택 영역이 프로그램 시작 시에 정해짐에 반해, 힙 영역은 런 타임에 프로그램이 OS에 요청하여 할당됩니다. 힙 영역은 할당 시마다 반드시 연속되어 할당되는 것이 아니기 때문에 할당 순서에 상관없이 해제할 수 있습니다.
프로그램 실행시 메모리가 할당되는 것을 동적할당이라고
프로그램 실행시 메모리가 할당되는 것을 동적할당이라고 합니다. 그리고 이 때 사용되는 메모리를 개념적으로 heap이라고 하는 것이고요. 그리고 동적할당된 메모리가 3개라면 그 3개를 모두 해제해주어야 합니다. 만약 하나라도 덜 해제해준다면, 메모리 누수라 하여 메모리가 회수되지 않을 경우가 생깁니다. 운영체제에 따라서는 자동으로 해제되기도 하는데, 운영체제가 해제해주기를 바라고 동적할당된 메모리를 해제해주지 않는 프로그램은 그 메모리의 회수가 운영체제에 종속적이기 때문에 좋은 프로그램이라고 할 수 없죠. 만약 운영체제가 메모리를 회수하지 않는 경우가 생긴다면, 정말로 메모리 누수가 발생하게 됩니다. 메모리 누수라 함은 메모리가 회수되지 않는 것을 의미합니다. 즉 메모리를 제대로 회수하지 않는 프로그램은 플랫폼에 종속적인 프로그램이 돼버립니다.
본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.
본인이 무슨 말을 하는지나 알고 글을 쓰시는지
본인이 무슨 말을 하는지나 알고 글을 쓰시는지 모르겠군요.
메모리 회수 여부와 플랫폼 종속 여부는 아무 관계가 없어요.
또, 프로그램이 종료하면 대부분의 메모리가 회수됩니다만,
실행 시에 OS가 메모리를 회수하는 경우는 없습니다.
오타군요. 그리고 실행시 회수한다고 한 적은 없습니다.
오타군요. 해제를 회수로 정정해야겠습니다. 그런데 실행시 OS가 회수한다고 한 적은 없습니다. 그 부분은 잘 못 이해하신 것 같습니다.
본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.
it's irrelevant.
it's irrelevant.
Quote:프로그램 실행시 메모리가 할당되는 것을
맞습니다. heap이 뭔지 아는 말은 아니지만.
(프로그램의 버그 등으로) 메모리가 회수되지 않는 현상 그 자체를 메모리 누수라 합니다.
리눅스, 윈도우 등의 통상적 운영체제들은 프로세스가 종료할 때 해당 프로세스가 사용하던 메모리 공간 전체를 회수합니다. 그러나 이 "회수"와, 프로그램이 제가 가진 힙에서 동적으로 할당한 메모리를 "회수"하는 것은 글자만 같을 뿐 전혀 다른 것을 의미합니다. 추상적 층위에서 추론하지 마세요. 즉 상상하지 마세요. 그건 학습과 practice를 대신한 게으름일 뿐입니다. 그 상상의 결과를 질문과 관계없는 답으로 다는 행동은 어떻게 보아도 좋게 볼 수 없군요.
상상 위에 쌓아 올린 허구입니다.
메모리 누수란
Quote(니 말)>
프로그램이 제가 가진 힙에서 동적으로 할당한 메모리를 "회수"
해제가 안 된 메모리가 다른 프로그램에서도 사용할 수 없는 상태가 돼버린 겁니다. 그런데 이것을 또 회수라고 말씀하시면 안되죠. 완전히 무개념이군요. OS는 회수. 그런데 프로그램이 회수? 잘 생각해보시길 바래.
종속적이라는 말에 대해 이해가 충분하지 않군요. 어떤 변수에 따라 그 결과가 변동될 경우를 종속적이라고 하는 것입니다. 먼저 종속이라는 것에 대한 사전적인 이해가 필요하겠군요. 국어공부를 도대체 어떻게 하셨길래 저런 개념을 모르나.
프로그램 공부하기 전에 국어 공부를 더 하셔야 겠어요. ㅋㅋ.
본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.
애쓴다..
자기 공부 덜 된 걸 남 탓 해봐야 소용없어요.
본인의 무지를 탓하세요.
아직도 종속이 뭔지 개념이 안 잡히나. x라는 변인에 의해 변하는 y를 종속적이라고 합니다. 소멸자 처리를 하지 않았을 때 플랫폼에 따라 메모리 누수가 생길 수도 있고 아닐 수도 있으니 플랫폼이라는 변인에 따라 메모리 누수라는 변인은 종속적이라고 할 수 있습니다. 그래서 종속이라 할 수 있다. 좀 종속에 대한 개념이 뭔지 공부를 하시라니까. 그리고 저 포인터 접근에 대한 것은 님이 아는 이상으로 나도 압니다.
본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.
아닙니다. 리눅스, 윈도우 같은 현대적인 OS에서는
아닙니다. 리눅스, 윈도우 같은 현대적인 OS에서는 한 프로그램에서 메모리릭이 발생해도 그게 곧바로 다른 프로그램의 메모리 가용 여부에 영향을 주지는 않습니다. 주소 공간이 다르기 때문입니다. 그래서 virtual address죠 ㅎㅎ
음...
실력이 부족해도 악으로 도전해오는 사람을 제가 많이 좋아하는데요, 이제 님과는 꺼려지네요 ㅎㅎ. 세 가지 이유입니다.
첫번째, 제 짐작이긴 하나 님은 이미 한 번 제가 도발하는 말에 정말로 상처 받았습니다. 더 이상은 서로 위험하고요.
둘째, 제가 님께 달아드린 gdb 답변 중에 틀린 게 하나 있습니다. 달고 나서도 긴가 민가 해서 확인했더니 틀려서 아차 싶었는데, 님 성격에 그냥 이죽대기만 하고 넘어가시더군요. 찾아보지도 않았다는 거죠.
셋째, 저는 님이 "잠시 착각"하신 걸 세 번 지적했습니다.
첫번째는 님께 하는 말도 아닌 제 말에 뜬금없는 반말로 달려드셨는데, 뭐 상황 상 그럴 수 있다 생각하고 또 저도 그걸 핑계로 거칠게 잘 놀았으니 됐습니다.
두번째는 서로 좋게 이야기 되었죠.
세번째는 인정 안하고 도망가셨죠. 음.. 여전히 상황 파악이 안되었을 수도 있겠으나 님의 마지막 댓글로 보건대 그건 아니라고 판단합니다 ㅎㅎ
인터넷으로 토론하다 혹은 감정싸움하다 도망가는 거 비일비재하고 또 그게 뭐 대수도 아닙니다만.. 글쎄 ㅎㅎ 무척 실망스러웠습니다.
제 판단이.
익명은 존재감이 없기 때문입니다.
익명 뒤에 숨어서 함부로 말하기 때문이죠라고 그쪽이 말씀했지만, 그렇지 않아요. 님이 남을 무시하는 어조로 말씀하셨지. 본인이 한 일을 기억못하는 까마귀이시군요.
님 의 quote> 첫번째, 제 짐작이긴 하나 님은 이미 한 번 제가 도발하는 말에 정말로 상처 받았습니다. 더 이상은 서로 위험하고요.
라고 말씀하셨는데. 천만에요. 상처 전혀 안 받았습니다. 님은 답변 달지 말라는 말에도 계속 답변만 달더군요. 님은 타자(나)에게 인정받고 싶은거에요. 그게 당신의 문제입니다. 싫으면 그냥 답변 달지 않으면 돼요. 당신한테 답변 달아달란 말 하지 않았으니. 본인이 상처 받아놓고 자신이 받은 상처 받은만큼 상대방이 상처받았으면 하는 너의 마음 상태가 문제인거에요. 아셨죠?
님의 quote> 둘째, 제가 님께 달아드린 gdb 답변 중에 틀린 게 하나 있습니다. 달고 나서도 긴가 민가 해서 확인했더니 틀려서 아차 싶었는데, 님 성격에 그냥 이죽대기만 하고 넘어가시더군요. 찾아보지도 않았다는 거죠.
마치 본인의 실수가 남의 실수인양 몰아붙이고 있죠? 그게 당신의 문제입니다. 님의 실수는 너의 실수로 끝나야죠. 그게 내 실수는 아니죠. 그리고 이죽대기 누가 이죽댑니까? 당신이 깐죽댄 적은 있어도.
님의 quote> 셋째, 저는 님이 "잠시 착각"하신 걸 세 번 지적했습니다.
님이 세 번 지적했는지 알 거 없어요. 님 같은 사람한테 물어본 것도 아닌데. 그리고 익명이 어디 한 둘인가? 님이 몇 번 지적한 것을 내가 기억할 수도 없을 뿐더러 기억할 필요도 없습니다.
여하튼 님의 문제를 남한테 떠넘기지 마세요. 사회에서 깨지기 쉬운 유형입니다. 가차없이 떼거리로 말입니다.
본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.
네, 맞습니다. 구체적으로 들어가지 못해 문제인
네, 맞습니다. 구체적으로 들어가지 못해 문제인 사람에게 벽만 더 높이는 이에게 한마디 했다가, 첨엔 뭐 이런 게 다 있지? 싶었지만, 뭐 옛날 생각도 나고 ㅎㅎ 역시 내 방식이 맞다는 걸 확인해보고 싶었습니다. 좀 더 나아가보지 못한 건 아쉽지만, 이 정도로 만족합니다.
기우였던 건 다행이네요 ㅎㅎ
기우였던 건 다행이네요 ㅎㅎ
아니 무슨 말싸가지들이
상대가 잘 모르는 것 같으면 친절히 알려 줄 생각을 해야지 시발 모른다고 무시하는것도 아니고 뭐 하는 놈들이야...
니들보다 더 뛰어나고 잘난 사람도 많다.
친절해라. 제발.
님이 상상의 결과를 사실인 양 써대는 한 님은
님이 상상의 결과를 사실인 양 써대는 한 님은 kldp에서 개무시 당할 겁니다, 님이 누구건.
성실하게 공부하는 학생의 자세를 보이는 한 존중받을 겁니다, 님이 누구건.
이참에 다시 한 번 토론하고 싶습니다.
http://kldp.org/node/142690
위 링크는 제가 나름대로 힙 메모리 영역을 구현한 것입니다.
(자료구조상의 힙이 아니라는 것은 인정합니다.)
처음에는 이걸 참고로 하면 힙을 이해하는 데 도움을 드릴 수 있을 것 같다는 생각을 했지만,
덧글들을 보니 문득 저도 제 맘대로 상상한 결과를 진짜라고 말해버릴 수 있겠다는 생각을 했습니다.
답변이 아니지만, 이걸 가지고 얘기를 나눠보면 저처럼 잘 모르는 사람들이 더 올바르게 힙을 이해할 수 있지 않을까 합니다.
저는 이렇게 생각했습니다.
doc 파일 열어만 보고 코드 분석은 안했습니다.
doc 파일 열어만 보고 코드 분석은 안했습니다.
원 글에서 어떤 분이 이미 잘 말씀해주셨듯, 메모리 관리자로서의 힙을 구현하셨다면 (별다른 버그가 없는 한) 그냥 제 기능을 잘 수행하는 힙이고, 아무 문제 없겠죠.
자료구조 상의 힙은 아니지만 이런 식의 구현은 어떨까라고 한다면, 코드 작성자로서 의사 코드와 그림 좀 그려서 발제해주시면 이야기 나누기 쉽지 않을까 합니다.
군 복무 중이신 것 같은데, 공부 열심히 하시네요.
제가 실수했군요.
코드 양이 길지 않아서 괜찮지 않을까 했는데 잘못 생각했습니다. 그림은 지금 좀 어려워서 어떻게 프로그램이 돌아가는지만 표현해봤습니다.
1. 시뮬레이션
2. free
3. alloc
4. 결과
이상입니다.
저는 이렇게 생각했습니다.
요 몇 주 전에요.
혹시 Effective C++읽으라고 권하셨던 분 아니신가요?
본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.
Effective C++를 읽으라는 답변을 단 적이 없습니다.
그렇습니다.
저는 이렇게 생각했습니다.
https://kldp.org/node/142984#
https://kldp.org/node/142984#comment-604302
음... 잘 모르겠는데요..
어떤 분을 위한 링크인가요? 여기에 제가 Effective C++를 읽으라고는 하지 않았으니 저는 아닐 것 같은데.
저는 이렇게 생각했습니다.
기본적으로 운영체제 책에 힙 영역 구현이 나와
기본적으로 운영체제 책에 힙 영역 구현이 나와 있습니다. 힙영역 자체는 일정한 메모리 영역에 불과합니다. 기본적으로 정확한 이해를 위해서는 메모리 계층구조에 대한 이해가 선행해야 하나, 간단하게만 설명해 드리겠습니다. 일단 user레벨(사용자의 프로그램)에서 malloc이나 new같은걸로 메모리 요청을 하면, 운영체제는 메모리 블록(4kb정도 단위)를 그 프로그램에 할당합니다. 그리고 그 영역중에 프로그램이 요청한 크기에 맞는 메모리 주소를 돌려줍니다. 그러면 다음번 요청에는 메모리 블록에 아직 사용가능한 영역이 좀 남았다면, 그 부분에서 할당해주고, 부족하다면 메모리 블록을 계속 늘려서 할당합니다. 그리고 이건 가상메모리상의 개념이기 때문에 실제로 하드웨어적인 메모리에 올라가는것이랑은 별 상관이 없습니다. 이런 방식때문에 메모리를 큰 객체와 작은 객체에 번갈아서 할당하게 되면, 프로그램에 사용한 메모리보다 최대 2배에 달하는 메모리가 할당됩니다.
여기서 운영체제는 메모리 블락 내부에 다음번에 할당할 메모리 영역을 계속해서 추적해야 합니다. 대부분의 운영체제는 linked list로 이 구조를 유지합니다. 이때 메모리 요청이 들어오면, list를 따라가면서 현재 요청된 크기의 메모리가 남아있는 블록까지 가서 그 주소를 돌려주고, 없다면 새로운 메모리 블록을 할당하는 겁니다.
메모리 블록 할당은 기본적으로 가상메모리의 기본적인 단위자, 실제 하드웨어 메모리와 cpu 캐쉬에 들어가는 기본단위기 때문에, 실제 하드웨어에 매핑되는 정보도 있어야 할겁니다. 이걸 프로세스의 page table에 기록해 둡니다. 그리고 캐쉬영역에 관한 정보를 CPU의 TLB에 기록합니다.
더욱 자세한 내용에 대해서는 OS책에 대부분 잘 설명되어 있고요, pintos manual과 소스를 보면, 어느정도 운영체제의 메모리 할당의 기본적인 구현에 대해서 보실 수 있습니다.
답변 감사합니다.
운영체제를 공부하려고 Operating System Concepts를 샀는데 이 책을 보면 될 것 같네요.
소중한 답변 감사합니다.
저는 이렇게 생각했습니다.
부연설명
쓰신 이야기에서 OS와 라이브러리의 역할 분담에 대해 약간 오해의 소지가 있어서...
Linux 같은 일반적인 운영체제를 기준으로 얘기하자면, malloc이나 new 같은 메모리 요청은 운영체제가 아니라 런타임 라이브러리에서 (Linux라면 glibc, libstdc++ 등등) 처리합니다. 여기서 기존에 할당받은 메모리 페이지 중 빈 공간이 있나 찾아보고, 있으면 그 부분을 할당해서 caller에게 돌려주고, 없을 때만 system call을 불러서 운영체제에 추가 메모리를 요청하게 됩니다.
따라서 운영체제는 이 프로그램이 어떤 메모리 주소를 사용중인지 페이지 단위로만 (일반적으로 4K) 정보를 갖고 있으며, 각각의 4K 중에서 어떤 부분이 현재 malloc/new 등으로 사용중인 부분이고 어디가 free된 부분인지는 런타임 라이브러리가 관리하는 부분이고 운영체제는 전혀 신경쓰지 않습니다.
그러니까 위의 글에서
> 이때 메모리 요청이 들어오면, list를 따라가면서 현재 요청된 크기의 메모리가 남아있는 블록까지 가서 그 주소를 돌려주고, ...
이 부분은 OS의 역할이 아닙니다. 기존의 페이지에 충분한 공간이 없어서 새로운 페이지를 할당하는 경우에만 OS가 불리게 됩니다.
이렇게 하는 주된 이유는 malloc이나 new는 굉장히 자주 불리기 때문에 그때마다 운영체제를 부르면 성능이 심각히 저하되기 때문입니다.
답변 2
1. 동적 할당이 세 번 일어나고 두 번째 것이 해제된다면.
당연히 p1, p3는 남아있고 p2는 해제됩니다. 다만 free 함수의 원형은 void free(void *p)로 인자로 넘긴 포인터 변수 자체의 값을 바꾸는 용도로 사용하지는 않습니다.
이 경우 p2를 인자로 넘긴다고 p2의 값(p2가 가리키는 값을 말하는 게 아닙니다)이 바뀌는 것은 아닙니다. call by value인데 당연하지요?
2. 아래는 사견입니다.
저는 예전에 힙에서 메모리를 해제하면 이전에 할당되었던 메모리를 당기던지 해서 빈 공간을 없앨 것이라 생각했는데,
메모리를 해제한다고 이전에 할당된 메모리를 옮겨버리면 이미 할당된 메모리를 가리키는 변수들은 쓰레기 값을 가리키게 됩니다.
(free 함수에 이전에 할당된 메모리를 가리키는 변수의 주솟값을 전달한다면 모를까..)
결론은 메모리를 해제한다고 이전에 할당된 메모리를 옮기지는 않는다는 뜻입니다. 위에 올린 '제가 만든 Heap'은 이러한 점을 고려해서
메모리 해제는 메모리 해제대로 수행하고, 할당은 hptr이라는 정적 변수를 통해 수행하고 있습니다.
이후에 메모리가 가득 차면 처음부터 탐색해서 빈 공간이 있을 때 할당하려는 것이죠.
이상입니다. 사견이라고 한 건 실제 Heap이 이렇게 동작한다는 문서를 본 적이 없고 제가 생각해낸 것이기 때문입니다.
ps. code 태그를 이용해 코드를 올리면 그 다음 문단부터 글이 자꾸 깨지는데 저만 이런가요?
IE 8, FIrefox 10, 30에서 모두 이렇습니다. 입력 형식을 바꿔봐도 계속 그러네요.
원래 참고용 코드를 작성했다가 글이 자꾸 깨지는 바람에 관뒀습니다.
저는 이렇게 생각했습니다.
댓글 달기