Post

크래프톤 정글 주제별 탐구 -메모리 구조-

정의

메모리 구조의 대한 간단한 설명을 해보고자 한다.

도입

메모리는 네가지 영역을 가지고 있다.

  1. 코드(code)영역
  2. 데이터(data)영역
  3. 힙(heap)영역
  4. 스택(stack)영역

이러한 메모리들은 각각 역할이 다르다.


코드(code) 영역

코드 영역의 경우, 프로그램의 코드가 저장되는 영역이며, 텍스트 영역이라고도 부른다. 여기에서 CPU는 실행할 명령어를 하나씩 가져가서 처리하게 된다.

데이터(data) 영역

데이터 영역의 경우, 프로그램의 전역변수와 정적(static)변수를 저장하는 공간이다. 이는 프로그램의 실행과 동시에 함께 할당되고, 프로그램이 종료되면 소멸하게 되는 영역이다.

스택(stack) 영역

스택 영역은 함수의 호출과 관계되는 지역 변수와 매개변수가 저장되는 영역이다. 스택 영역은 함수의 호출과 함께 할당되고, 함수의 호출이 완료되면 소멸한다. 이 함수는 당연하게도 main 함수도 포함한다. 이렇게 스택 영역에 저장되는 함수의 호출 정보를 스택 프레임(Stack Frame)이라고 하며, 재귀 호출이 반복적으로 진행되었을 때, 이러한 스택 프레임이 다수 쌓이게 되며, 이 때 이 스택 데이터가 힙 영역을 침범하게 되는 경우, 힙 영역의 데이터가 오염되며 이를 우리는 ‘스택 오버플로우(Stack Overflow)’라고 부른다.

함수의 호출이 스택 부분에 들어가고, 이에 따라 늦게 호출된 함수가 먼저 작동하고 이전 함수로 돌아가기 때문에, 중간에 함수를 진행하고 함수 진행 이전 상태로 돌아가 코드를 마저 진행할 수 있다.

또한, 스택이라는 이름에 걸맞게, 스택 방식으로 구현되어 있기에, 메모리의 높은 주소에서 낮은 주소의 방향으로 할당된다.

TCP School(ㅋㅋ TCP 프로토콜로 원격 수업을 진행하나봄)이라는 웹 사이트에서 설명을 조금 깔끔하게 해두었길래, 그 사진을 조금 가져와봤다. 해당 웹사이트에서는 C언어를 기반으로 제작해두었길래, 현재 정글에서 쓰고 있는 python으로 조금 기반 코드를 수정하여 가져와보자면…

1
2
3
4
5
6
7
8
9
10
11
12
13
main():
    func1()
    return 0

func1():
    func2()
    return

func2():
    return

if __name__ == "__main__":
	main()

위와 같은 코드가 있다고 가정하자.

이를 잠시 순서에 나누어 설명해보자.

  1. 프로그램 실행 시, main() 이 호출되어, 이것의 스택 프레임이 메모리의 스택 공간에 저장된다.
  2. func1() 함수가 호출되고, 이의 매개변수, 반환 주소값, 지역 변수 등이 스택 프레임으로 스택 공간에 저장된다.
  3. func2() 함수를 호출하면 해당 함수의 스택 프레임이 추가로 스택에 저장된다.
  4. func2() 함수가 종료되면 func2()함수의 스택 프레임이 스택 공간에서 제거된다.
  5. func1() 함수의 스택 프레임이 동일하게 제거된다.
  6. main() 함수도 동일하게 스택 프레임이 제거된다.

이러한 방식으로 스택 공간은 사용된다.

힙(heap) 영역

힙 영역은 사용자가 직접 관리할 수 있는, 그리고 직접 관리 해야만 하는 메모리 영역이다. 힙 영역은 사용자에 의해 메모리 공간이 동적으로 할당되고 해제되며, 힙 영역은 메모리의 낮은 주소에서 높은 주소의 방향으로 할당된다.

스택과 데이터 영역의 할당될 메모리의 크기는 컴파일 타임(Compile Time)에 미리 결정되는데, 힙 영역의 경우에는 프로그램이 실행중인 런 타임(Run Time)에 사용자가 직접 결정하게 된다. 이러한 방식으로 인해 메모리가 가변적으로 크기가 변동되는 것을 우리는 동적 할당(Dynamic Allocation)이라고 한다.

이를 통제하는 것이 데이터 공간을 할당하는 malloc() 함수와 이를 해제하는 free()함수인데, 이는 C언어 공부를 할 때 조금 더 자세히 다뤄보도록 하겠다. 또한, 비슷하게 calloc() 함수도 존재하는데, 이는 malloc()과는 다르게 메모리의 크기를 두개의 인수로 나누어 전달받으며, 메모리를 할당받은 후 해당 메모리의 모든 비트값을 0으로 초기화시킨다. 이 역시 free()로 해제하는 것을 잊지 말아야 한다.

realloc()함수는 이미 할당된 메모리의 크기를 재할당 시키는 것이다.

This post is licensed under CC BY 4.0 by the author.