프로그래밍/C++

C++ 메모리 구조

Rozentea 2024. 1. 29. 19:05
해당 글은 공부를 하면서 적은 글이기 때문에 틀릴 수 있습니다. 참고용으로만 봐주세요~

 

0. 개요


프로그램이 실행되기 위해서 먼저 프로그램이 메모리에 로드되어야 한다.

뿐만 아니라 프로그램에서 사용되는 변수들을 저장할 메모리도 필요하다.

 

메모리는 물리적 메모리(Physical Memory)와 가상 메모리(Virtual Memory)로 나뉩니다.

일반적으로 코드를 실행하면 가상 메모리에 적재됩니다.

 

물리적 메모리는 RAM이고 가상 메모리는 HDD의 용량에서 가져와 사용하게 됩니다.

운영체제는 프로그램을 실행할 때 필요한 최소정보만 RAM에 저장합니다.

그리고 이를 Working set이라고 합니다.

 

그 후 프로그램을 실행하면서 필요한 데이터 정보를 가상 메모리에서 가져와 상황에 맞게 물리적 메모리에 맵핑하고 맵핑을 해제하는 반복 작업을 하게됩니다.

이것을 페이징(Paging) 기법이라고 합니다.

 

가상 메모리의 주소 데이터들을 일정한 크기의 블록으로 쪼개 놓은걸 페이지(Page)라고 하며

물리 메모리의 주소 데이터들을 일정한 크기의 블록으로 쪼개 놓은걸 프레임(Frame)이라고 합니다.

 

그래서 같은 크기의 블록들을 메모리에 맵핑하며 프로그램이 동작하게 됩니다.

이렇게 나눈 이유는 CPU의 부담을 덜어주기 위함 입니다.

(너무 작은 데이터 단위면 작업이 빈번히 많이 일어나기 때문입니다.)

그림으로 단순히 표현하면 이런식입니다.

 

메모리에 대한 간략한 설명을 마쳤으니 이제 메모리 구조에 대해 알아봅시다.

1. 메모리 구조


개요에서 살펴본 것과 같이 프로그램이 실행되기 위해서는 메모리에 로드되어야 한다. OS는 프로그램의 실행을 위해 다양한 메모리 공간을 제공하고 있는데 대표적으로 프로그램이 OS로 부터 할당받는 메모리 공간은 다음과 같다.

a. 코드(Code) 영역

메모리의 코드영역은 프로그램의 코드와 매크로 상수가 기계어의 형태로 저장되는 영역으로 CPU는 코드영역에 저장된 명령어를 하나씩 가져가 처리한다.

이러한 코드 영역은 컴파일 타임에 결정되고 중간에 코드를 바꿀 수 없게 Read-Only로 지정되어 있다.

 

b. 데이터(Data) 영역

메모리의 데이터영역은 프로그램의 전역변수와 정적(static)변수가 저장되는 영역이며, 프로그램의 시작과 함께 할당되며 프로그램이 종료하면 소멸한다.

전역 변수 / static 값을 참조한 코드는 컴파일하고 나면 Data영역의 주소값을 가르키도록 바뀐다.

실행 도중에 전역변수가 변경될 수도 있으니 이 영역은 Read-Write로 지정되어 있다.

단, 초기화 되지 않은 전역변수는 BSS 영역에 할당된다.

 

c. 스택(Stack) 영역

메모리의 스택영역은 함수의 호출과 관계되는 지역변수와 매개변수가 저장되는 영역이다.

스택영역은 함수의 호출과 함께 할당되며, 함수의 호출이 완료되면 소멸한다.

이렇게 스택에 저장되는 함수의 호출 정보를 스택 프레임이라 한다. 스택영역은 메모리의 높은 주소에서 낮은 주소의 방향으로 할단된다.

 

스택영역의 크기는 컴파일 타임에 정해지고, 할당되는 공간이 작다. (보통 1mb)

컴파일 타임에 크기가 정해지기 때문에 무한히 할당할 수 없다.

때문에 재귀함수가 너무 깊게 호출되거나 함수가 지역변수를 너무 많이 가지고 있으면 Stack영역을 벗어나 Stack Overflow가 발생하게 된다.

 

또한 함수의 호출과 관계되는 지역변수, 매개변수 뿐만 아니라 리턴값, 돌아올 주소 등등이 함께 저장된다.

기록하고 종료하는 메커니즘은 자료구조의 Stack과 동일하게 후위선출(LIFO)방식을 따른다.

 

d. 힙(Heap) 영역

메모리의 힙영역은 사용자가 직접 관리할 수 있는 메모리 영역이다.

사용자에 의해 메모리 공간이 동적으로 할당되고 해제된다.

힙영역은 메모리의 낮은 주소에서 높은 주소의 방향으로 할당된다.

 

Code, Data, Stack 영역과는 다르게 Heap 영역은 런타임에 결정된다.

new, malloc() 등으로 Heap 영역을 사용할 수 있다.

사용작가 직접 메모리 공간을 동적으로 할당하기 때문에 반드시 사용하고 난 뒤에는 delete, free()를 이용해 메모리를 해제해주어야 한다.

그렇지 않는다면 메모리릭이 발생하게 된다.

(초창기 스마트폰을 사용할 때 위젯을 설치해서 계속 프로그램들을 종료시켜 주어야했던 이유가 바로 이것 때문이다.)

 

Heap영역은 비교적 크다. (32bit 최대 4GB - 모든 프로그램)

스택영역보다 할당할 수 있는 메모리 공간이 많다는 장점이 있지만, 포인터로 메모리 영역을 접근해야 하기 때문에 다른 메모리 공간에 비해서 데이터를 읽고 쓰는게 느리다.

 

컴파일 타임과 런타임

런타임(Runtime)과 컴파일타임(Compiletime)은 소프트웨어 프로그램 개발의 서로 다른 두 계층의 차이를 설명하기 위한 용어이다.

프로그램을 생성하기 위해 개발자는 첫째로 소스코드를 작성하고 컴파일이라는 과정을 통해 기계어 코드로 변환되어 실행 가능한 프로그램이 되며, 이러한 편집 과정을 컴파일타임(Compiletime)이라고 부른다.

 

컴파일과정을 마친 프로그램은 사용자에 의해 실행되어지며, 이러한 응용프로그램이 동작되어지는 때를 런타임(Runtime)이라고 부른다.

 

런타임과 컴파일 타임이라는 용어는 종종 서로 다른 두 가지 타입의 에러를 나타내기 위해 사용되어지곤 하는데, 컴파일 타임에러는 프로그램이 성공적으로 컴파일링되는 것을 방해하는 신택스에러(Syntax error)나 파일 참조 오류와 같은 문제를 말하며, 이런 경우 컴파일러는 컴파일 타임에러를 발생시키고 일반적으로 문제를 일으킨 소스코드 라인을 지시해준다.

 

만약, 어떤 소스코드가 이미 실행한 프로그램으로 컴파일 되었다 할지라도 이것은 여전히 프로그램의 실행중에 버그를 일으킬 수 있다.

예를 들자면, 예상치 못한 오류 또는 충돌로 동작하지 않을 수 있는데 이렇게 프로그램이 실행중에 발생하는 형태의 오류를 런타임 오류라고 한다.

 

즉, 프로그램이 실행 중일 때를 런타임이라 부르고, 프로그램 빌드 등등의 작업을 할 때를 컴파일 타임이라고 보면 된다.

 

스택 영역과 힙 영역이 서로 다른 방향으로 주소가 할당되는 이유

스택 영역과 힙 영역이 서로 다른 방향으로 주소가 할당되는 이유는 버퍼오버플로우(Buffer Overflow)를 막기 위해서 입니다.

스택 영역의 뒤에는 커널 영역이 존재합니다.

옛날, 변수에 스택영역이 초과되는 크기의 데이터를 저장한 후 커널영역에 침범해 데이터를 조작하여 관리자 권한 같은 해킹을 많이 했었습니다.

 

이런 사고를 막고자 스택 영역은 큰 주소 값을 시작으로 점차 아래로 주소 값이 할당되는 것입니다.

(지금도 Buffer Overflow는 많이 사용되고 있습니다. 구글링을 통해 리눅스의 관리자 권한 취득하는 툴을 검색하면 대부분 Buffer Overflow 기법으로 해킹되는 install툴이 많은 것을 알 수 있습니다.)

 

또한 BufferOverflow를 막기위해 주소 할당 방법 뿐 아니라 매 실행마다 주소 값 또한 바뀌도록 만들고, 메모리상에 각 변수마다 메모리 할당이 넉넉히 되도록 만들었습니다.

(코드상 int는 4바이트, double은 8바이트 이지만 변수와 변수 사이 공간은 int는 12바이트, double은 15바이트씩 차지하고 있습니다.)

 

이러한 것들은 결국 원치 않는 데이터 침범을 막기 위함이라고 합니다.

 

스택 프레임

함수가 호출되면 스택에는 함수의 매개변수, 호출이 끝난 뒤 돌아갈 반환 주소값, 함수에서 선언된 지역 변수 등이 저장된다.

이렇게 스택영역에 차례대로 저장되는 함수의 호출 정보를 스택 프레임이라고 한다.

이러한 스택 프레임 덕분에 함수의 호출이 모두 끝난 뒤에, 해당 함수가 호출되기 이전 상태로 되돌아갈 수 있다.

 

4. 참고 문헌


 

[C++] 메모리 구조

메모리 구조 프로그램이 실행되기 위해서는 먼저 프로그램이 메모리에 로드(load)되어야 하는데, 프로그램에서 사용되는 변수들을 저장할 메모리도 필요하다. 따라서 OS는 프로그램의 실행을 위

returnclass.tistory.com

 

 

메모리 구조에 대해서(stack, heap, buffer overflow)

프로그램을 만들고 실행을 하게되면 메모리 라는 곳에 코드들이 올라가 실행되게 됩니다. 사실 메모리는 물리적 메모리(Physical Memory)와 가상 메모리(Virtual Memory)로 나뉘게 됩니다.일반적으로 코

hwan-shell.tistory.com

 

 

<C++ 기초> 메모리 구조 힙, 스택, 데이터, 코드

더보기 Code 영역 프로세스가 실행할 코드와 매크로 상수가 기계어의 형태로 저장된 공간이다. 컴파일 타임에 결정되고 중간에 코드를 바꿀 수 없게 Read-Only 로 지정돼있다. Data 영역 코드에서 선

nybot-house.tistory.com