간혹 스택과 힙의 차이를 이렇게 이해하는 경우가 있음.
스택 == 크기 불변, 메모리 주소상 연속적
힙 == 크기 변화 자유로움, 메모리 주소상 비연속적
이 오해는 좀 더 나아가면 C에서 포인터가 중요한 이유는 힙에서 대규모 메모리를 자유롭게 할당받아 사용할 수 있게 해주기 때문이라 생각하기까지 하게 됨. 그렇게 사용할 수 있는 것은 사실이고 많은 사람들이 그렇게 사용하는 것도 사실이지만, 그건 좀 핀트가 어긋난 이해라 할 수 있음.
왜냐면 스택도 런타임 와중 크기가 분명 변하며 심지어 많은 OS에서 그 최대크기를 무제한으로 설정할 수 있기 때문임. 그리고 그 과정에서 당연하지만 데이터는 '물리적' 주소 상으로 볼 시 비연속적으로 저장되게 됨. 리눅스의 경우에는 그냥 ulimit -s unlimited 를 입력하면 되니까 그리 어려운 것도 아님. 힙에는 별거 없는데 스택이 10gb인 프로세스도 얼마든지 존재할 수 있는거지.
여담이지만 그렇기에 흔히 C에서 배열의 길이는 상수로밖에 정할 수 없고 그것은 스택의 길이가 compile-time에 constant해야하기에 그렇다라고 듣는 말 역시 구라임. 실제로는 C99 스탠다드에 이미 VLA(variable-length array)라고 변수값으로 배열의 길이를 선언할 수 있는 기능이 포함되어 있음. 보통 스택 오버플로우 에러 뜨기 쉬워 컴파일러들이 이 기능 끌 수 있는 옵션을 넣고 그게 디폴트 옵션이라 모를 뿐이지.
내 생각에 스택과 힙의 차이는 이렇게 보는게 더 맞다고 본다.
스택 == 변수 그리고 따라서 메모리 자원의 획득, 놓아주기 및 참조가 지역적으로 이루어짐.
힙 == 변수 그리고 따라서 메모리 자원의 획득, 놓아주기 및 참조가 프로그래머 꼴리는대로 이루어짐.
여담이지만 스택의 크기가 어떻게 무제한적으로 불어나게 할 수 있는지 그 원리가 궁금하면 MMU(memory management unit), 그리고 가상 메모리 공간(virtual memory space)과 물리적 메모리 공간(physical memory space)에 대해 알아보고 그 후 리눅스/윈도우즈에서는 각 프로세스마다 독자적이고 서로 다른 개별적 가상 메모리 공간을 하나씩 할당한다는 것을 곱씹어보면 쉬움.
와 몰랐네
그런데 프로그램 내부에서 스택 크기를 늘리게 할 수 있음?
OS에서 스택 최대 크기를 되게 크게 혹은 무제한으로 설정해놓으면 됨.
그러면 스택의 크기가 커지면서 더 많은 메모리를 할당받아 점유하게 되고 줄어들면 다시 그걸 놓아주게 되는거지.
프로그램 내부에서 스택 최대 크기 설정을 바꾸는건 아마 정상적인 수단으로는 안 될거 같음.
그건 커널쪽 수치를 수정하는것이니 유저 프로그램에서 가능하다면 보안 문제일듯.
그러면 "좀 더 나아가면 C에서 포인터가 중요한 이유는 힙에서 대규모 메모리를 자유롭게 할당받아 사용할 수 있게 해주기 때문이라 생각하기까지 하게 됨. "이 거짓말은 아니네
ㅇㅇ 그래서 그게 거짓말이라고는 하지 않음. 다만 핀트에 어긋난 이해라고 했지.
물리주소는 프로그래머가 아예 접근도 안되는 데, 그걸 기준으로 스택도 불연속하다고 말하는 건 아닌듯
스택은 적어도 space locality 면에서 더 우위에 있는거 아님?
스택 크기가 무제한이여야 한다는 말 저거 운영체제 과제할 때 교수가 그렇게 구현하라고 하다가 리눅스도 그렇게 안 되어 있어서 취소했음. 일반적으로는 페이지 디렉토리 한 엔트리가 최대임
그리고 물리적으로는 비연속적인 것은 중요하지 않음. 중요한 것은 프로세스 입장에서 연속적인 것임.
물리주소 기준으로 연속성 운운한건 확실히 좀 무리수이긴 했다. 그건 인정.
근데 리눅스는 프로세스마다 가상 메모리 공간 하나씩 할당하는 방법이고 구체적으로는 mm_struct 구조체를 하나씩 할당해 그 안에 vm_area_struct 구조체에 대한 포인터를 가지고 그 구조체가 스택이니 힙이니 하는 메모리 영역들을 담당하는 구조라서 실제로 스택 크기 무제한 될텐데.
무제한은 몰랐네