ILoveCoffee, ILoveJava

변수(전역, 지역, 매개, static) 저장 위치

jeeyong 2008. 1. 19. 13:52
번에 알아볼 내용은 변수 입니다.  '변수'  사실 프로그래밍 하면서 많이 선언하고 사용하지만 이 변수가 어디에 어떻게 저장되고 불려 오는지 생각해보신 분은 사실 그리 많지 않을 것 입니다. 하지만 알고 나면 아하 그래서 이렇게 사용할 수 있구나 라든가 고급스런 프로그래밍에서 예를 들면 재귀호출과 같은 프로그램밍시에 어떻게 작동을 해서 결과를 넘겨주는지를 이해할 수 있게 될 것입니다. 상당히 추상적인 개념인지라 약간의 상상력을 요할 수 있는 이론입니다. 제가 씨(C/C++)을 공부하던 시기에 봤던 문서를 좀더 이해하기 쉽게 풀어서 나중에 까먹거나 했을 경우 보고 회상하기위해 작성한 글이기 때문에 다소 주관적인 스타일로 작성될 수도 있겠습니다. 

그럼 본론으로 들어가 보겠습니다.

게 보면 프로그램은 code와 그 프로그램에서 사용하는 data로 구성됩니다. 하지만 좀더 세분할 경우 크게code(text), data, heap, stack 이렇게 4개로 나눌 수 있으며, 각각을 세그먼트(segment) 라고 합니다. 이렇게 글을 쓰는건 별루 좋아하지 않거니와 글제주도 없기 때문에 그림으로 설명드리겠습니다.


사용자 삽입 이미지
 code(text) 영역은 프로그램의 code 자체를 구성하는 명령이나, 기계어 명령이 존재하고, 이 부분은 read only입니다. 그러므로 이곳에 데이터를 쓰려면 access violation 을 발생 시킵니다. CPU 가 읽어 들여 수행한다고 해서 text라고 부르며, code영역 이라고도합니다.
 Data 영역은 전역(global)변수, 정적(static)변수, 초기화된 배열과 그 구조들이 저장되는 영역이고, 이 영역은 프로그램이 실행될 때 생성되고 프로그램이 종료될 대 시스템에 반환됩니다.
 heap 영역은 프로그래머가 필요에 의해서 동적으로 할당되는 메모리가 위치하는 영역입니다. 즉, C++(또는 JAVA)에서 new 나 C 에서 malloc 으로 할당하는 것으로 C 또는 C++에서는 해제를 해줘야 하지만 자바의 경우엔 자동으로 가비지콜랙터(GarbageCollector)에 의해 자동으로 해체가 이루어집니다.
 끝으로 stack 영역엔 지역(local)변수 및 매개변수(parameter), 복귀 번지(retrun address) 등등이 저장되어 있는 곳입니다. 함수 호출시에 역시 stack 영역에 생성되고 사용된 후 시스템에 반환됩니다. 또한 함수로 인수(argument)를 보낼 때는 인수(argument)를 역순으로 보낸 뒤 복귀 번지(return address)를 저장합니다. 따라서 선입후출(First In Last Out)의 형태가 됩니다.

code(text), data, heap 영역( 이 중 data 영역은 compile-time 때에 결정되어지고, heap영역은 run-time시 요구할 때마다 사용되어집니다.) 은 하위 메모리로부터 할당되며, stack영역은 상위 메모리로 부터 할당되어 집니다.

 의 그림을 가지고 설명하자면 그림의 화살표를 참조하면 처음 컴파일시에 소스코드를 하위메모리에 할당하고 그 다음 전역(global)변수, 정적(static)변수를 data영역에서 할당하는것입니다. 그리고 heap영역은 런타임시에 필요에 따라 객체를 생성하면서 stack이 있는 방향으로 할당되거나 해제 되고 stack은 반대로 높은 주소 번지에서 시작해서 낮은 번지로 할당되거나 해제 되는것입니다.
 이처럼 우리가 프로그램을 실행하면 OS kernel에서 제어에 적합한 자료구조로 만들어 메모리로 읽어내어 동작하게 되는 것입니다.

 우리가 프로그램을 짤 때 프로그래머가 동적으로 할당 가능한 heap 영역을 제외하고는 나머지 영역은 컴파일러에 의해서 결정됩니다.
 따라서 code(text), data, stack영역은 최소한 프로그램 실행 이전에 모든 정보를 운영체제에게 알려줘야 합니다. 그래서 compile-time 에 data 영역 및 stack 영역의 크기를 계산해서 필요한 메모리 공간의 정보를 파일에 함께 갖게 됩니다.( 그래서 C 언어에서 배열을 선언할 때 #1)incomplete type으로 사용하면 컴파일 할 때 에러가 발생되는 겁니다. 물론 배열형 매개변수는 사이즈를 정해주지 않고 사용해도 포인터로 변환이 되므로 사용가능 합니다. 이 경우엔 에러나 경고가 뜨는 컴파일러도 있습니다만 ISO/IEC에서 명백하게 규정된 것은 아니므로 잘못된 문법이라고는 할 수 없습니다.)

 으로 운영체제는 각각의 프로세스 간에 메모리 영역을 침범하지 못하도록 합니다. 즉, 같은 메모리를 필요에 의해서 구분해 놓은 것이라 할지라도 각 영역들 사이는 서로 오갈 수 없습니다. 윈도우에서 "잘못된 연산을 수행해 프로그램을 종료합니다"란 에러 메시지는 대부분 이런 이유에서 발생합니다.

#1)incomplete type : 1. 불완전 타입. 예) int a[i];
                             2. 자바에선 특이하게도 가능하다 물론 메모리 자체를 직접 다루지않고 JVM이 관리하고있기 때문인지도 모르겠다. 혹은 배열도 객체로 취급하기때문에 heap영역으로 가지않을까 그래서 가능한거 같다. 예) int a[] = new int[i];