1.메모리 영역
C++ 환경은 메모리를 효율적으로 관리하기 위해서 메모리를 여러 영역으로 나눕니다
2.코드 메모리
코드 메모리(code memory)는 프로그램 코드를 보유하는 영역입니다. 프로그램이 실행될 때 C++ 실행 환경은 코드 메모리 위에 있는 문장을 하나하나 실행합니다. 코드 메모리는 프로그램이 종료될 때 해제됩니다.
3.정적 메모리
정적 메모리(static memory)는 전역 객체(global object)(전역 객체는 어떤 함수에도 속하지 않는 함수 외부에 있는 객체)**와 정적 객체(static object)**를 보유하는 영역입니다. 프로그램이 종료되면 모든 객체들을 정리하고 메모리 위에서 해제합니다.
/**************************************************************
* 프로그램이 존재하는 *
* 동안 계속해서 메모리에 존재하는 *
* 전역 변수, 정적 변수를 사용하는 프로그램 *
**************************************************************/
#include <iostream>
using namespace std;
int first = 20; // 정적 메모리 위에 올라가는 전역 변수
static int second = 30 ; // 정적 메모리 위에 올라가는 전역 정적 변수
int main()
{
static int third = 50; // 정적 메모리 위에 올라가는 정적 변수
cout << "전역 변수의 값: " << first << endl; // 20
cout << "전역 정적 변수의 값: " << second << endl; // 30
cout << "지역 정적 변수의 값: " << third; // 50
return 0;
}
4.스택 메모리
스택 메모리(stack memory)는 함수의 지역 변수와 매개변수를 보유합니다.
스택이란 후입선출(last-in-first-out) 컨테이너로 마지막에 넣은 것이 가장 먼저 꺼내지는 자료 구조입니다. 스택의 이러한 특성은 함수의 지역 변수와 매개변수를 저장하는 데 적합합니다. 함수를 호출하면 시스템은 지역 변수와 매개변수를 스택 메모리에 삽입(push)합니다. 그리고 함수가 종료하면 이러한 것들을 삭제(pop)해서 버립니다.
장점
객체는 함수 스코프 내부에 있을 때만 스택 메모리에 유지되며, 함수의 스코프를 벗어나면 삭제되어서 더 이상 접근할 수 없게 됩니다.
제한
- 컴파일 시점에 객체의 이름을 정의해야 합니다
- 컴파일 시점에 객체의 크기를 정의해야 합니다.
이러한 이유로 스택 메모리를 컴파일 시점 메모리(compile-time memory)라고 부르기도 합니다. 스택 메모리에 저장할 모든 객체는 컴파일 시점에 확실하게 이름과 크기가 정의되어 있어야 합니다.
#include <iostream>
using namespace std;
int main()
{
int size;
cin >> size;
double array[size]; // 컴파일 오류
...
return 0;
}
지역 변수 array를 스택 메모리에 저장하려면, 컴파일 시점에 배열의 크기를 알아야 하기 때문에 컴파일 오류가 발생합니다. 이와 같은 가변 배열을 만들고 싶으면 힙 메모리라는 영역을 사용해야 합니다.
5.힙 메모리
프로그램을 컴파일하는 시점에 객체의 크기를 모른다면, 런타임 시점에 메모리에 객체를 만들어야 합니다. 힙 메모리(heap memory)는 런타임 시점에 객체를 저장할 때 사용합니다. 여유 메모리(free memory) 또는 동적 메모리(dynamic memory)라고도 부릅니다.
C++는 스택에 있는 객체만 이름을 가질 수 있습니다. 따라서 힙 메모리의 객체는 자신의 이름을 가질 수 없습니다. 힙 메모리에 생성한 객체는 스택 메모리에 있는 포인터로 가리켜야 합니다. 즉 런타임 시점에 메모리에 객체를 만드는 작업은 스택과 힙을 모두 사용하는 것입니다. 스택 메모리에는 4바이트의 작은 포인터를 만들고 힙 메모리에는 큰 객체를 생성하여 포인터가 큰 객체를 가리키게 합니다.
포인터는 스택 메모리에, 포인트되는 객체는 힙 메모리에 있음!
new와 delete 연산자
그럼 런타임 시점에 어떤 코드로 힙에 객체를 만들 수 있을까요? 그리고 사용을 모두 완료해서 더 이상 필요가 없어진 힙에 있는 객체를 어떻게 제거할 수 있을까요?
힙에 메모리 할당과 해제를 위한 연산자
그룹 | 이름 | 연산자 | 표현식 | 우선 순위 | 결합방향 |
단항 | 객체 할당 배열 할당 객체 제거 배열 제거 |
new new[] delete delete[] |
new type new type[size] delete ptr delete[] ptr |
17 | ← |
참고로 delete를 하면 해당 포인터는 허상 포인터(dangling pointer)가 됩니다. 허상 포인터는 new 연산자를 적용하기 전까지는 사용할 수 없습니다.
/**************************************************************
* 힙 메모리에 크기가 유동적인 배열을 만들고 *
* 포인터로 요소에 접근하는 프로그램 *
**************************************************************/
#include <iostream>
using namespace std;
int main()
{
// 스택에 배열에 대한 크기와 포인터 선언
int size;
int* pArray;
// 사용자로부터 0보다 큰 배열의 크기 입력받기
do
{
cout << "0보다 큰 배열의 크기를 입력하세요:";
cin >> size;
} while(size <= 0);
// 힙에 배열 생성
pArray = new int[size];
// 배열에 값 입력받기
for(int i = 0; i < size ; i++)
{
cout << i << "번째 요소의 값을 입력하세요: ";
cin >> *(pArray + i);
}
// 배열의 요소 출력
cout << "배열 내부의 요소:" << endl;
for(int i = 0; i < size ; i++)
{
cout << *(pArray + i) << " ";
}
// 힙에서 배열 제거
delete [] pArray;
return 0;
}
힙 메모리와 관련된 문제
힙 메모리, 힙 메모리와 관련된 연산자(new, delete)를 사용할 때는 주의할 점이 있습니다
1. 메모리 할당 없이 제거
new 키워드를 사용하지 않았는데 delete 키워드를 사용하는 경우, 즉 힙 메모리에 메모리 할당을 하지 않았는데 제거하려는 경우입니다.
일반적으로 스택에 할당한 객체를 제거하려고 하다가 발생하는 경우가 많습니다.
double x = 23.4;
double* pX = &x; // 스택에 할당되어 있음
delete pX; // 그런데 힙 메모리에서 제거하므로 런타임 오류가 발생
2. 제거 없이 메모리 할당하기(메모리 누수)
메모리 누수는 new 키워드로 힙 메모리 위에 영역을 잡은 뒤, delete 키워드로 제거하지 않았을 때 발생합니다.
double* pX = new double; // 할당된 메모리 사용
...
포인터 변수가 스코프를 벗어나버리면, 포인터 변수가 사라집니다. 따라서 더 이상 해당 메모리 위치를 가리킬 수 있는 방법이 없습니다. 해당 메모리 위치를 제거할 수 있는 방법도 사라집니다. 이를 메모리 누수라고 부릅니다. 메모리 누수가 발생하면 누수가 발생한 메모리 위치를 사용할 수 없으며, 메모리가 부족한 경우에는 시스템에 큰 문제를 야기할 수도 있습니다.
3. 허상 포인터
허상 포인터(dangling pointer)는 포인터가 가리키고 있는 객체를 delete 키워드로 제거했는데, 포인터를 활용하려고 할 때 발생합니다.
double* pX = new double;
... // 할당된 메모리 사용
delete pX;
*pX = 35.3; // 허상 포인터 문제 발생
마지막 행에서 오류가 발생합니다. 포인터가 널이므로, 포인터를 사용해서 메모리 위치의 값에 접근할 수 없습니다.
출처 : 포르잔 C++ 바이블
'내일배움캠프 > TIL' 카테고리의 다른 글
[내일배움캠프 Day12] 반복자와 포인터 (2) | 2025.01.02 |
---|---|
[내일배움캠프 Day11] 템플릿 (3) | 2024.12.31 |
[내일배움캠프 Day9] 포인터 (0) | 2024.12.27 |
[내일배움캠프 Day8] C++ 과제 진행 (2) | 2024.12.26 |
[내일배움캠프 Day7] Git (1) | 2024.12.24 |