스택 메모리는 함수 호출시 자동으로 할당되는 해제되는 메모리 공간이다. 주로 함수의 로컬 변수와 매개 변수가 저장
#include <iostream> using namespace std; void func1() { int a = 10; // 지역 변수 'a', stack 메모리에서 관리됨 cout << "func1: a = " << a << endl; } // func1()이 종료되면 'a'는 소멸됨 int main() { func1(); // func1() 호출 // 'a'는 func1() 호출 중에만 존재하고, 함수 종료 후 소멸됨 return 0; }
힙 메모리는 동적으로 메모리를 할당(New)하고 해제(delete)하는 데 사용하는 메모리 공간이다. 일반적으로 객체, 배열 및 기타 데이터 구조를 저장하는 데 사용
#include <iostream> using namespace std; void func2() { int* arr = new int[5]; // 힙 메모리에 정수 배열 5개 할당 for (int i = 0; i < 5; ++i) { arr[i] = i * 10; cout << "arr[" << i << "] = " << arr[i] << endl; } delete[] arr; // 배열 메모리 해제 } int main() { func2(); return 0; }
스택 메모리와 힙 메모리는 각각의 용도에 따라 적절하게 사용해야 한다. 스택은 간단한 로컬 변수와 매개변수에 적합하고, 힙은 동적으로 크기가 변할 수 있는 데이터 구조에 적합하다.
void function() { int x = 10; // 함수 시작 시 생성 if (true) { int y = 20; // 블록 시작 시 생성 cout << y << endl; } // y는 여기서 소멸 // cout << y << endl; // 에러! y는 이미 소멸됨 } // x는 여기서 소멸특징
- 수명 : 선언된 블록이 실행되는 동안
- 범위 : 선언된 블록 내부
- 초기화 : 자동으로 초기화되지 않음 (쓰레기 값 가능)
#include <iostream> using namespace std; int globalVar = 100; // 전역 변수 void function1() { cout << globalVar << endl; // 접근 가능 globalVar = 200; // 수정 가능 } void function2() { cout << globalVar << endl; // 200 출력 } int main() { cout << globalVar << endl; // 100 출력 function1(); function2(); return 0; } // 프로그램 종료 시 globalVar 소멸특징
- 수명 : 프로그램 전체 실행 기간
- 범위 : 프로그램 전체
- 초기화 : 자동으로 0으로 초기화
정적 지역 변수(Static Local Variable)
- 함수 내부에서 static 으로 선언
- 첫 호출 시 한번만 초기화
- 함수가 끝나도 값이 유지
- 해당 함수에서만 접근 가능
#include <iostream> using namespace std; void counter() { static int count = 0; // 첫 호출 시 한 번만 초기화 count++; cout << "호출 횟수: " << count << endl; } int main() { counter(); // 출력: 호출 횟수: 1 counter(); // 출력: 호출 횟수: 2 counter(); // 출력: 호출 횟수: 3 return 0; } // count는 프로그램 종료 시 소멸
정적 전역 변수 (Static Global Variable)
- 파일 외부에서 static 으로 선언
- 해당 파일 내에서만 접근 가능
- 내부 연결
// file1.cpp static int fileVar = 100; // 정적 전역 변수 (file1.cpp에서만 접근 가능) void function1() { cout << fileVar << endl; // 접근 가능 } // file2.cpp // extern int fileVar; // 에러! static 변수는 다른 파일에서 접근 불가 void function2() { // cout << fileVar << endl; // 에러! }extern 키워드는 C/C++에서 여러 파일로 구성된 프로젝트에서 전역 변수를 공유할 때 사용한다.
정적 멤버 변수 (Static Member Variable)
- 클래스 내부에서 static 으로 선언
- 모든 객체가 공유하는 변수
- 클래스 외부에서 정의해야함
- 객체 없이도 접근 가능
#include <iostream> using namespace std; class MyClass { public: // 정적 멤버 변수 선언 static int count; int id; MyClass() { id = count++; // 각 객체에 고유 ID 부여 } // 정적 멤버 함수 static void printCount() { cout << "생성된 객체 수: " << count << endl; } }; // 정적 멤버 변수 정의 (클래스 외부) int MyClass::count = 0; int main() { cout << "초기 count: " << MyClass::count << endl; // 0 MyClass::printCount(); MyClass obj1; // count = 1 MyClass obj2; // count = 2 MyClass obj3; // count = 3 cout << "obj1 Count: " << obj1.count << endl; // 3 cout << "obj2 Count: " << obj2.count << endl; // 3 cout << "obj3 Count: " << obj3.count << endl; // 3 cout << "obj1 ID: " << obj1.id << endl; // 0 cout << "obj2 ID: " << obj2.id << endl; // 1 cout << "obj3 ID: " << obj3.id << endl; // 2 MyClass::printCount(); return 0; }
#include <iostream> using namespace std; int main() { int size = 5; int* arr = new int[size]; // 배열 동적 할당 for (int i = 0; i < size; i++) { arr[i] = i * 10; } for (int i = 0; i < size; i++) { cout << arr[i] << endl; } delete[] arr; // 배열은 delete[] 사용 return 0; }특징
- 수명 : delete 호출 시까지
- 범위 : 포인터가 유효한 곳이면 접근 가능
- 주의 : 메모리 누수 방지를 위해 delete 해야함
#include <iostream> using namespace std; void modify(int x) { x = 100; // 복사본 수정 } int main() { int a = 10; modify(a); cout << a << endl; // 10 (원본 변경 안 됨) return 0; }
프로그램이 동적으로 할당된 메모리를 사용 후 적절하게 해제하지 않아, 더 이상 접근할 수 없게 되는 상황을 의미한다. 이러한 누수는 메모리가 점진적으로 소모되어 시스템 성능 저하를 초래하고, 프로그램이 사용할 수 있는 메모리가 부족해지는 결과를 가져올 수 있다.
#include <iostream> using namespace std; void func3() { int* ptr = new int(20); // 힙 메모리에 정수 20 할당 cout << "Value: " << *ptr << endl; // 메모리 해제를 하지 않음 } int main() { func3(); // 메모리 누수 발생 return 0; }
- 참조 손실 : 할당된 메모리의 포인터를 다른 주소로 변경하거나 NULL로 설정하면 원래 메모리에 대한 참조가 사라져 해제할 수 없게 된다.
#include <iostream> using namespace std; void func3() { int* ptr = new int(20); // 힙 메모리에 정수 20 할당 cout << "Value: " << *ptr << endl; ptr = nullptr; // 할당한 메모리 참조가 nullptr로 바껴서 해제 불가 } int main() { func3(); // 메모리 누수 발생 return 0; }
- 예외 처리 부족 : 예외가 발생했을 때, 할당된 메모리를 해제하지 않고 프로그램이 종료되면 메모리 누수가 발생할 수 있다.
메모리 누수는 프로그래밍에서 흔히 발생할 수 있는 문제로, 이를 방지하기 위해서는 메모리 관리를 철저히 하고, 적절한 도구를 활용하는 것이 중요하다.