반응형

C언어가 사용하는 메모리 구조


XCode를 이용하였지만, 보는데에는 큰 지장이 없습니다.


1. C언어가 사용하는 메모리

C언어의 메모리 관리와 관련된 이미지를 검색해보면 정말 다양한 내용들을 볼 수 있었다. 근데 조금씩 다르다. 그래서 위키를 기본으로해서 내용을 증명해가는 방식으로 진행해보도록 해보겠다.


<출처 : https://ko.wikipedia.org/wiki/동적_메모리_할당>



위 이미지가 C언어의 메모리구조라고 나와있는 그림이다. 이미지에 나와있는 예시들을 통하여 실제 데이터의 주소를 알아보도록 하겠다.



2) STACK영역


먼저 지역변수가 저장되는 STACK영역이다.


   

< 좌측 : 코드     우측 : 실행결과 >

(왜인지 변수를 초기화 안해도 쓰레기 값이 아닌 0이 들어가있다. XCode라 그런가...?)


< 변수 cnt의 메모리상 위치 >


위키의 내용에 따르면 현재 cnt라는 지역변수가 저장되어있는 '0x7ffeefbff53c'라는 위치는 STACK영역의 가장 하단부분이 해당될 것이다.


그렇다면 STACK영역보다 아래(더 뒤에있는 영역)는?


         

< 좌 : 코드     우 : 실행결과 >


위 결과와 같이 이후의 영역의 내용을 불러와도 정상적으로 값을 불러오는 것을 보면, 이 부분 역시 해당 프로그램이 사용하는 영역이라는 것을 알 수 있다.


이부분에 대한것은 아쉽게도 위키의 이미지에서는 찾아볼 수 없다. 따라서 이부분은 나중에 확인해보도록 하자.



그럼 다음으로 넘어가기전에 왜 이 영역을 STACK영역이라고 부르는지 알아보도록 하자.


이유는 다음 코드와 메모리의 상태를 보면 알 수 있다.


< 코드 >



< 메모리 공간상 위치 >


위의 내용을 보게되면, cnt1 ~ 3의 순서로 선언했음에도 메모리에는 cnt3이 가장 먼저 보이는 결과를 알 수 있다.


이것은 STACK이라는 영역은 선언되는 변수에게 공간을 할당할 때, STACK영역의 가장 마지막 부분부터 공간을 할당한다는 것을 의미한다.


만약 STACK이라는 자료구조를 알고있다면, 쉽게 이해가 가능할 것이다.


다만 이게 정해진 규칙은 아니다. 메모리관리는 운영체제에 따라 달라질 수 있다. 지금 내가 작업중인 맥OS(XCode)에서는 위와같이 작동했지만, 다른 운영체제, 다른 IDE에서는 다른 규칙에 따라서 작업을 수행할 것이다.



그런데 문제가 있다. 바로 배열을 선언했을 때인데, 아래 그림을 보면서 생각해보자.


< 코드 >


< 메모리 공간상 위치 >


이제까지 내용을 기본으로하면 [ cnt3 - arr2 - cnt2 - arr1 - cnt1 ]의 순서로 메모리에 데이터들이 쌓여있어야 하는데, 실제 데이터의 위치를보면, [cnt3~1 - arr2 - arr1] 순서로 스택에 데이터가 쌓여있는 것을 볼 수 있다. 또한, 각 데이터들의 사이사이에 불필요해보이는 메모리 공간이 보이는 것을 알 수 있다.


어째서일까? 한번 생각해보도록 하자


3) HEAP 영역

HEAP영역은 [ 동적 메모리 할당 ]이라는 녀석을 다루는데 있어서 빠질 수 없는 장소이다. 왜냐하면 malloc이라는 함수를 통해서 변수가 할당받는 메모리가 HEAP영역이기 때문이다.



< 코드 >


다음과 같은 코드를 작성했다고 해보자, [ int *heap_data ] 라고 선언한걸보면, heap_data 라는 녀석은 특정한 주소값을 갖고 있다는 것을 알 수 있다. 그렇다면 메모리 영역에서 이것들이 어떤식으로 존재하는지 확인해보자.


< heap_data 의 메모리상 위치 >



< *heap_data의 메모리상 위치 >


위에 두 그림 중 위에있는 이미지를 먼저 확인해보자, 


위에있는 녀석은 주소값을 갖고있는 포인터이다. 64bit 컴퓨터에서 메모리 공간을 포인팅하기 위해서는 동일한 64bit가 필요하다. 따라서 총 8byte의 공간이 할당되었다.


리틀엔디언 방식을 따르기때문에 뒤에서부터 두개씩 읽어야하는데, 읽어보면 [ 00 00 00 01 00 64 1A E0 ]  라는 주소값을 갖고있는 것을 알 수 있다. 그럼 해당주소를 확인해보자.


두번째 그림이 해당주소를 확인해본 결과이다. (놀랍게도? 아니면 당연하게도?) 해당 주소에는 코드에서 지정한것과 같은 값이 저장되어있는 것을 알 수 있다.




그럼 정리해보자, C언어에서 데이터를 참조하기 위해서는 변수가 필요하다. 여기서 heap_data라는 녀석은 하나의 포인터 변수이다. 이녀석은 이전에 말했던 STACK영역에 존재한다.


하지만, 이 녀석이 가리키고있는 데이터[ *heap_data ]는 동적할당받은 HEAP영역에 존재한다.




4) STACK과 HEAP의 확장

C언어의 메모리에 대해서 관심을 갖고 찾아보다보면 아래와 같은 그림을 볼 수 있다.


이 그림에서 중점적으로 봐야할 부분은 바로 회색 화살표이다. 그렇다고 'HEAP영역은 위에서 아래로 데이터 공간을 할당하고,  STACK영역은 아래서 위로 데이터 공간을 할당한다.' 라고 하는 것은아니다. 


다만 OS라고하는 운영체제는 미래를 알지는 못해서 프로그램이 수행되는 과정에서 얼마만큼의 동적할당이 발생할지, 스택영역은 정확하게 얼마만큼이 필요한지 정확하게 알지 못한다. 그렇기 때문에 적당한 메모리를 할당하고, 이후 추가적으로 메모리가 필요할 경우 두 위 그림과 같은 방향으로 프로그램이 가용할 수 있는 메모리 크기를 확장한다.


그렇다면 HEAP영역을 무한히 늘리면 언제가는 스택영역을 침범하지 않을까? 하는 의문이 발생한다.


생각해보자.



반응형

+ Recent posts