C++ 에서는 메모리를 직접 운영해야 한다.

 

다른 많은 프로그래밍 언어에서 가상머신이 메모리를 관리해주는 것에 비해서 C++에서는 메모리를 직접 운영하기 때문에 메모리의 구조에 대한 지식이 필요하다.

 

프로그래머가 알아야 하는 메모리 종류는 다음과 같다.

 

- 전역변수 공간

 

- 힙 메모리

 

- 레지스터

 

- 코드 공간

 

- 스택 메모리

 

1. 스택메모리

 

C++ 프로그램을 실행하면 main 함수가 먼저 실행된다. main 함수는 자신의 지역변수(local variable)을 가지고 있다. 즉 main 함수안의  { } 중괄호는 지역임을 의미한다.

 

보통 C++을 처음 시작할 때 이 내용에 대해 충분히 설명하지 않는다.

 

필자는 첫번째 챕터부터 Hello World 의 원리에 대하여 모든 것을 설명하고 싶은 충동을 느끼곤 한다. 그런데 자세한 설명은 처음 코드를 타이핑하는 사람에게는 너무 가혹한 일이 될 수 있다.

 

대부분의 프로그래밍 튜토리얼에서 '이것은 지금 몰라도 됩니다' 라는 말을 남발하는게 개인취향으로는 별로지만 그것이 보통의 교습법인 것 같다. 코딩 유튜브에서는 프로그래머 강사들이 항상 하는 입버릇, '이거는 지금 몰라도 되고요, 나중에 가면 알게 됩니다' 라는 댓글이 몇백개의 공감을 얻곤 한다.

 

그런걸 보면 프로그래밍이란 물리학이나 수학같은 자연과학에서 처럼 이해를 바탕으로 하는 학문은 아닌 것 같다. 국내에서 유명한 코딩도장의 표어는 '프로그래밍은 공부가 아닙니다. 연습입니다' 라고 한다. 드롭박스 창업자 드류

 휴스턴의 말처럼 프로그래밍은 악기 연주와 비슷한 속성이 있다. 연습을 하고 내공을 쌓는 과정에서 완성되는 분야지 자연과학처럼 어떤 우주의 원리를 설명하고 실험하는 일과는 좀 거리가 있다.

 

그러고보니 프로그래밍에 대해서는 고수라는 말을 많이 쓰고 프로그래밍 박사라는 말은 좀처럼 사용하지 않는다.

 

프로그래밍을 시작할 때 누군가 이런 접근 방식을 가르쳐줬다면 어떨까 생각이 든다.

 

어쨋든 초급 단계에서 Hello World 같은 프로그래밍을 작성할 때나 또는 업무자동화 정도의 일을 하기 위해서 메모리의 구조를 이해할 필요는 없지만 C++을 선택하였다면 메모리에 대하여 통달해야 한다. 아마 그게 잘 안되는 경우 포인터 챕터를 좀 보다가 그만 두게 되는 것 같다. 다행히 이제는 컴퓨터공학을 전공해도 굳이 C++을 선택하지 않아도 되는 시대가 되었다. 어느 언어가 더 뛰어난가에 대한 단순한 비교를 하는게 아니고 C++과 다른 언어의 차이를 구분할 필요가 있다.

 

컴퓨터공학자들이 이 차이를 잘 알기 때문에 managed 와 unmanaged 라는 개념을 나누었다. managed 는 가상머신이 메모리를 관리하는(managed) 언어를 지칭하는 단어이고 unmanaged는 가상머신이 관리하지 않기 때문에 프로그래머가 메모리를 매니징 해야하는 C언어/C++을 말한다. 

 

*이제 마음을 가다듬고 다음의 코드에서 스택 메모리를 찾아보자.

int main()
{
	int localVar = 10;

	return 0;
}

main 은 처음으로 로드되는 함수다. 함수는 하나의 구역(지역)을 가지고 있다. 일본어로는 국소 변수라고 한다. 같은 한자어 문화권인데 번역에 차이가 있어서 조사를 해보니 국소변수는 전체에서 특정 집단의 소속감을 강조하는 단어다. 즉 main에 소속된 변수가 국소변수 우리말로는 지역변수다. localVar 는 main에 완전히 소속된 변수로 다른 지역에서 사용할 수 없고 만약에 이 지역이 사라지면(메모리에서 해제되면) 자신의 지역과 함께 사라진다. 이 지역을 떠나서 살 수 없는 변수를 지역변수라 한다.

 

그리고 지역변수는 항상 스택메모리에 저장된다. 이것이 스택메모리다.

 

* 참고 링크 - 지역변수와 전역변수

 

C++ | 함수 | 지역변수, 전역변수 | 용어 해설 | 국소변수, 광역변수 | 로컬변수 | 글로벌변수 (tistory.com)

 

C++ | 함수 | 지역변수, 전역변수 | 용어 해설 | 국소변수, 광역변수 | 로컬변수 | 글로벌변수

지역변수(Local Variables)의 개념이 좀 낯설다. 변수가 뭔지는 이제 알겠는데 지역변수는 무엇일까? 한글로 지역 변수라 번역했지만 영어로 local variable이다. 구글 사전 정의에 따르면 local은... -> belo

digiconfactory.tistory.com

다음의 예제 코드에서 스택메모리의 흐름을 따라가 보자.

#include <iostream>

using namespace std;

int square(int x)
{
	return x * x;
}

int main()
{
	int localVar = 10;
	int result = 0;

	result = square(localVar);
	cout << "result : " << result << endl;

	return 0;
}

main 지역에는 두 개의 지역변수 localVar 와 result 가 스택메모리에 저장된다.

 

main 에서 호출한 square 함수는 인수로 localVar 를 전달 받아서 매개변수인 x에 복사한다. 이 시점에서 스택에 x를 생성하고 함수의 실행을 완료한 후에 결과값을 main의 지역변수인 result 에게 대입한다. 대입이 끝나면 square 함수의 지역변수인 x는 스택 메모리에서 해제된다. 지역변수는 소속된 함수가 사라지면 함께 사라진다. 그렇기 때문에 square 함수를 호출한 main은 반환값을 자신의 지역변수인 result 에게 복사한다.

 

main 함수 자신도 코드의 마지막 줄에 가면 return 0과 함께 자신의 메모리를 해제한다. return 0 -> 0을 누구한테 보내는 것인가? C++을 호출한 운영체제 (C++ runtime)에게 전달한다. 일반적으로 0은 프로그램이 정상적으로 종료되었다는 것을 의미한다. 런타임 에러가 발생하면 별도의 리턴값을 전달 할 수 있다.

 

여기까지 스택의 관점에서 코드를 읽어봤다.

 

 

언뜻 보면 같은 값을 가지고 복사하는 행위가 너무 많아 보인다. 예제는 단순한 설명을 위한 10줄 남짓의 코드지만 이 코드가 만약 10줄이 아니라 100줄 1000줄 1만줄이 된다면? 값을 복사하는 이 방법이 파워를 발휘한다. 우선 사용이 끝난 메모리를 즉시 해제하기 때문에 적은 메모리로도 많은 작업을 실행할 수 잇다. 8비트 게임기의 슈퍼마리오 1탄은 이 방식이 없었다면 메모리 부족으로 실행이 불가능했을 것이다.

컴퓨터 게임을 개발하던 C++의 고인물들은 메모리 관리의 장인들이기도 한데 이분들의 나이가 벌써 환갑이 되서 많이들 은퇴하셨을 것이다. 슈퍼마리오가 1985년에 출시되었으니 35년 전이다. 메모리를 열심히 아끼고 아껴서 그 당시 낼수있는 한계의 성능을 보여줬다.

 

현재의 슈퍼마리오가 사용하는 메모리의 양은 수백배 이상 증가했고 여전히 게이머들에게 사랑받고 있다. 그래픽 프로세서의 발달이 가장 주요하지만 한몫하겠지만 메모리의 양이 늘었다는 것은 사람들이 잘 이야기를 안한다.

 

닌텐도 스위치의 슈퍼마리오 2019년

 

당시의 사양을 보면 시스템이 SRAM 2KB + 비디오램 SRAM 2KB 였다.

 

 

닌텐도 스위치는DDR4 SDRAM이 4GB 다... 저 사양에 비디오램은 표시가 안되있다. RAM의 크키가 닌텐도 패밀리보다 2의 20승 많으니까 100만배 인 것이다. 85년도의 닌텐도게임기와 2020년의 게임기는 메모리에서 어마어마한 차이를 보여준다.

요즘 보통 저사양의 PC를 구성할 때도 최소 8기가로 시작하는 것 같다. 16기가나 32기가를 다는 PC도 늘어나는 추세다.

 

과거에 비해 컴퓨터의 메모리가 100만배 많아졌다고 해서 현대의 프로그래머들이 방만하게 메모리를 사용하는가? 그것은 아니다. 과거에 비해 메모리를 많이 사용하고 있고 뒤에서 돌아가는 프로그램(데몬)도 많아져서 메모리를 효율적으로 사용하는 것은 지금도 중요한 문제다. 다만 JVM 같은 가상머신이 메모리를 잘 관리해주기 때문에 큰 문제 없이 사용하고 있는 것이다.

 

그래도 아직까지 C++이 주로 사용되는 분야는 CPU 성능을 최대로 끌어내야 하는 분야가 많다. 가상머신보다 인간의 코드가 더 필요하다는 이야기로 볼 수도 있는데 이것도 점점 바뀌어 가는 것만은 분명하다. 성능이 필요한 부분은 C++로 작성하고 전체를 움직이는 프레임워크는 스크립트 언어를 사용하는 경우도 많아지고 있다.

 

스택메모리에 대한 내용을 정리하려고 했는데 잡설이 길어진 것 같다. 딱히 교재라고 생각하고 작성한 포스트는 아니긴 하다. 메모리에 대한 전반적인 이야기를 하다보니 좀 길어졌다.


스택 메모리에 대해서 한 가지 더 알아야 하는 것은 프로그래머들이 수십년간 경험을 해보니 변수는 최대한 지역에 묶어놓는게 좋다라는 결론을 얻었다고 한다. 전역변수를 많이 사용하면 편하고 좋을 것 같지만 코드가 조금이라도 복잡해지면 문제가 생기기 쉽고 또 전역변수는 프로그램이 종료되기 전까지 해제되지 않기 때문에 메모리를 많이 사용한다. 때문에 프로그래머는 스택 메모리와 힙 메모리를 조화롭게 운영할 수 있어야 한다.

 

스택에 대한 포스팅은 이 정도에서 마무리한다. 메모리에 대한 포스팅은 가끔 하는 편인데 나중에 또 스택에 대한 자세한 내용을 포스팅 할 것 같다.

공유하기

facebook twitter kakaoTalk kakaostory naver band