개요
제가 저번 글에서 예고했듯이 이번 글은 메모리와 빌드입니다.
...
그러고보니 저번 글을 쓴게 언제였죠?
우와... 자그마치 6일전입니다.
메모리와 빌드는 거의 2주에서 3주 전 진도인데 이제야 정리하기 시작하는게 참 양심없긴 하지만...
월요일에 갑자기 몸살이 찾아온 뒤로 현재 위치가 집인 상황에서 후딱 해치우겠습니다.
아, 그리고 저번 글의 제목도 원래는 '열거형과 힙' 이였습니다.
근데 어짜피 메모리 정리할때 힙도 정리할텐데 굳이 애매한 분량으로 정리해야 하나 해서 분리시켰죠.
라고 적었는데 메모리 분량이 생각보다 길어서 분리시키겠습니다.
뭔가 했던말 같죠? 익숙하다면 당신의 눈이 정확한겁니다!
빌드는 다음 글로 작성하겠습니다. 꼭! 일주일 안에 뵙죠.
메모리
선생님 가라사대, C++에서 메모리는 매우 중요하다.
메모리... 그러니까 메모리 구조는 스택(Stack), 힙(Heap), 데이터(Data), 코드(Code)로 나눠져 있습니다.
우리가 여기서 제대로 알아야 하는 것은 스택, 힙, 데이터가 끝입니다. 코드는 머릿속에서 지워도 됩니다.
코드 영역은 저도 뭔지 모르고 몰라도 됩니다.
스택 (Stack)
스택... 이건 자료구조로도 있죠?
자료구조로써의 스택은 나중에 들어온 것이 (Last In) 먼저 나가는 (First Out) 구조를 갖고 있습니다.
데이터 영역으로써의 스택도 마찬가지입니다.
물론 그건 딱히 중요하지 않습니다. 우리가 알아야할건 스택에서 어떻게 데이터가 할당되고 제거되는가죠.
결론부터 말하자면 우리가 함수에서 선언한 변수들은 전부 스택에 들어갑니다.
그리고 함수가 끝날때 모두 제거되죠.
void func();
int main()
{
int a = 4;
}
void func()
{
cout << a; // 되겠냐?
}
그래서 어떠한 함수에서 그 함수 외의 다른 함수에서 선언된 변수를 가져올 수 없는 것이죠.
데이터 (Data)
힙을 다루기 전에 간단하게 데이터를 다루겠습니다.
데이터 영역에 들어가는 변수들은 정적 (static) 이거나 전역 변수입니다.
정적 변수나 전역 변수들은 프로그램이 시작될때 데이터 영역에 할당되며 프로그램이 끝날 때 제거됩니다.
int a = 4;
int main()
{
cout << a;
}
그렇기 때문에 어디서든 접근이 가능하죠.
그러면 여기서 질문이 하나 있습니다.
함수 안에서 선언된 정적 변수는 스택에 할당될까요?
결론부터 말하자면 아닙니다.
정적 변수들은 프로그램이 시작될때 싹 다 데이터 영역에 들어갑니다.
그리고 그 함수가 시작할때 초기화 되는 것 뿐입니다.
그렇기 때문에 전역 변수를 사용하지 않아도 지속적인 값을 유지하는 변수를 만들 수 있죠.
void update();
int main()
{
while(true)
{
update();
}
}
void update()
{
static int a = 0, b = 0; //처음 호출 될때 0으로 초기화됨.
a++;
b++;
}
위 코드에서 a와 b는 계속해서 증가합니다.
일반 변수였다면 0에서 1로 증가했다가 다시 0으로 초기화되고 다시 1로 증가했다가...
무한루프를 돌았겠죠.
힙 (Heap)
C#만 해온 온실속 화초인 우리가 드디어 무언가 만질 수 있는 부분입니다.
Garbage Collector가 해주던 데이터 관리를 이제 우리가 우리 손으로 해줄 때가 왔습니다...
C++에선 new, delete 키워드를 통해 힙에 데이터를 할당하고 제거할 수 있습니다.
물론 C#에서도 마찬가지로 new 키워드를 통해 힙에 데이터를 할당할 수 있지만
delete 키워드가 존재하지 않는 것이 차이점이라고 할 수 있겠죠.
new를 통해 힙에서 데이터를 할당하려면 포인터 변수가 필요합니다.
int* a = new int;
다음과 같이 선언된 포인터는 힙 영역에 그 자료형의 크기 만큼 할당된 데이터의 주소를 가르킵니다.
그렇기 때문에 포인터 변수는 스택에, 본래 값은 힙에 할당되는 것이죠.
여기서 문제점이 하나 있습니다.
컴퓨터는 모든 값을 주소로 판단합니다. 메모리 구조는 마치 map 처럼 주소와 값을 하나씩 짝지어서 할당합니다.
근데 그 주소를 가르키는 변수가 사라져서 접근할 방법이 완전히 사라졌을때, 그 값은 대체 어떻게 될까요?
지워질까요?
... 아뇨, 그건 C#의 가비지 콜렉터가 해주던 일이지 C++에선 프로그래머의 역량입니다.
제가 스택에 할당된 변수들은 함수가 끝나면 모두 지워진다고 했죠?
그렇다면 힙에 할당된 데이터를 가르키는 스택의 포인터 변수가 함수가 끝나서 지워졌을땐 힙에 할당된 데이터에 접근할 방법이 완전히 사라집니다.
그래서 더이상 사용할 방법이 없는 데이터가 힙에 남아서 지워지지 않는 현상을
메모리 누수 현상(memory leak) 이라고 합니다.
그렇기 때문에 delete 키워드를 사용해서 이미 사용이 끝난 데이터를 제때 지워줘야 합니다.
동적 배열
힙 영역에 데이터를 할당하기 위해선 new 키워드를 사용해야 한다고 했었죠?
new 키워드는 ....
여기까지 쓰고 동적 배열에 관해 실험 좀 해보려고 VS2022를 켰습니다.
근데 제가 이해하는 상식과 조금 충돌하는 부분이 있어서 검색도 해보고 AI도 닦달해봤단 말이죠?
아무래도 이해가 안됩니다. 동적 배열에 관한 부분은 바로 다음글에 적겠습니다. 빌드야 미안해!
마치는 말
동적 배열에 관한 글 쓰러 튀겠습니다. 지금 뇌에서 뭔가 일어나고있어요.
선생님께 연락하기엔 너무 이른시간이기 때문에 일단 글부터 좀 줄줄 써놓고 질문 리스트를 정리해놔야겠습니다 빠잇
'개발 > C++' 카테고리의 다른 글
자료구조 | C++ | 연산자 오버로딩 (Overload) (1) | 2024.04.23 |
---|---|
C++ | 동적 배열 (3) | 2024.04.17 |
게임 프로그래밍 | C++ | 열거형 (1) | 2024.04.10 |
게임 프로그래밍 | C++ | 콘솔 / 입력 (1) | 2024.04.08 |
자료구조 | C++ | 클래스 (1) | 2024.04.05 |