우리가 쓴 코드 한 줄은 CPU 안에서 정확히 어떻게 실행될까요? CPU는 만능 기계가 아니라 버튼이 몇 개 안 되는 리모컨이어서, 한 줄이 버튼 여러 번으로 쪼개집니다.
컴퓨터는 결국 아주 빠른 계산기입니다. 우리가 작성한 코드는 컴파일이나 해석을 거쳐 CPU가 이해하는 아주 단순한 명령들의 목록이 되고, CPU는 그 목록을 위에서부터 하나씩 실행합니다. 이 단원에서는 그 "하나씩"이 실제로 어떤 순서로 일어나는지, 함수를 호출하면 무엇이 어디에 기록되는지, 그리고 데이터가 메모리 어디에 놓이는지를 봅니다. 아래 애니메이션을 단계 버튼으로 직접 넘겨보면서 읽으면 가장 좋습니다.
CPU는 (1) 다음에 실행할 명령을 메모리에서 가져오고(인출), (2) 그게 무슨 뜻인지 해석하고, (3) 실행합니다. 이 세 가지를 초당 수십억 번 반복하는 것이 전부입니다. 우리가 "프로그램이 돈다"고 부르는 현상은 이 반복이 빠르게 이어지는 것뿐입니다.
메모리는 1바이트짜리 칸이 길게 늘어선 것이고, 각 칸에는 0번, 1번, 2번… 하는 번호가 붙어 있습니다. 이 번호를 주소라고 부릅니다. CPU는 "몇 번 칸의 값을 가져와라", "몇 번 칸에 이 값을 넣어라" 같은 식으로만 메모리를 다룹니다. 변수 이름은 사람이 쓰기 편하라고 붙인 이름표일 뿐, 실제로는 전부 주소로 번역됩니다.
메모리는 CPU 입장에서 꽤 먼 곳입니다(수십~수백 배 느립니다). 그래서 CPU 안에는 값 몇 개만 담아두는 초고속 저장소가 있는데, 이것이 레지스터입니다. 그중 특별한 레지스터 하나가 PC(프로그램 카운터)로, "다음에 실행할 명령이 몇 번 줄(주소)인지"를 담고 있습니다. 오른쪽 패널에서 PC 값이 바뀌는 걸 보면, 실행이 어디로 흘러가는지가 그대로 보입니다.
함수를 호출하면 그 함수의 지역변수를 놓을 자리가 필요합니다. 이 자리를 스택 프레임이라고 하고, 호출할 때 쌓고(push) 끝나면 걷어냅니다(pop). 접시를 쌓듯 마지막에 올린 것이 먼저 내려오기 때문에 스택(더미)이라고 부릅니다. 중요한 건 프레임에 지역변수만 들어가는 게 아니라는 점입니다 — "이 함수가 끝나면 돌아갈 주소"도 함께 적힙니다. return이 어디로 돌아갈지 아는 비밀이 바로 이것입니다.
배열이나 객체처럼 크기가 크거나, 함수가 끝난 뒤에도 살아 있어야 하는 데이터는 스택에 두기 곤란합니다(프레임이 사라지면 같이 사라지니까요). 그래서 이런 데이터는 힙이라는 별도 영역에 놓고, 스택에는 그 데이터가 있는 위치만 적어둡니다. 이 페이지에서는 힙 상자마다 @1, @2 같은 주소표를 붙이고 스택 변수는 그 번호만 들게 그렸습니다. 스택의 @1과 힙 상자의 @1이 같은 번호인지 확인하며 보세요.
1main() {2 prices = [12000, 8000]PC ◀3 total = sum(prices)4 print(total)5}6sum(list) {7 t = 08 for n in list: t += n9 return t10}
실행은 main의 첫 줄에서 시작합니다 — 아래의 sum(6~10번 줄)은 "정의"일 뿐, 호출되기 전엔 실행되지 않습니다. CPU는 PC(프로그램 카운터) 레지스터에 "지금 실행할 줄"을 들고 있습니다: PC = 2. 배열 실물은 힙 상자에 담기고 주소표 @1이 붙습니다. 스택의 prices에는 그 번호만 적힙니다.
시뮬레이터에서 해보기
이 단원의 용어
호출 = 복귀 주소 등록 + 점프. return = 그 주소로 복귀.
남은 문제
그런데 힙에 놓인 상자들은 언제, 누가 치울까요? 프로그램을 오래 켜두면 메모리는 왜 점점 찰까요? →