일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- Unity
- Java
- 뮤텍스
- 동기화
- unorderedset
- NotFoundException: String resource ID #0x0
- 유니티
- ARface
- semaphore
- unityAR
- 포톤
- 안드로이드스튜디오
- 지크슈
- map
- 세마포
- StartActivityForResult
- 광유다
- SpinLock
- Vector
- mutex
- 게임개발
- registerForActivityResult
- list
- 유니티슈팅게임
- C++
- 스핀락
- dependencyResilutionManagement
- 바이너리세마포
- photon
- unorderedmap
- Today
- Total
와와
힙(Heap)과 스택(Stack)과 메모리 할당과 해제 본문
스택 메모리
- 정적 할당, 컴파일 시간에 크기가 결정됨, 함수 호출 시 자동 할당되고 함수 종료 시 자동 해제됨
- LIFO(Last In First Out)방식으로 관리되며, 메모리 관리가 간단하고 빠르다. 스택의 크기는 제한적이기 때문에 큰 데이터를 저장하기에는 적합하지 않다.
정적 할당: Static Allocation
- 변수/객체의 크기와 수명이 컴파일 시간에 결정된다.
힙 메모리
- 동적 할당, 프로그램 실행 중에 크기가 결정되며, 개발자가 'new' 연산자를 사용하여 메모리를 할당하고, 'delete' 연산자를 사용하여 메모리를 해제한다.
- 스택에 비해 관리가 복잡하고 할당 및 해제 속도가 느리다. 그러나 메모리의 크기 제한이 스택보다 유연하여 큰 데이터를 저장하기에 적합하다.
동적 할당: Dynamic Allocation
- 프로그램 실행 중에 변수/객체의 크기가 결정된다. 할당 해제를 수동으로 관리해주어야 함.
메모리 구조
- 코드 영역: 프로그램의 실행 코드가 저장됨
- 데이터 영역: 전역, 정적 변수가 저장됨. 프로그램 시작 시 할당, 종료 시 해제
- 스택 영역: 함수의 지역 변수와 매개변수가 저장되는 영역. 함수 호출 시 할당, 함수 반환 시 해제
- 힙 영역: 동적으로 할당된 데이터(예: 'new'연산자로 생성된 객체)가 저장되는 영역. 사용자가 직접 관리

저장되는 영역과 인스턴스를 예시로 보자면
#include <iostream>
using namespace std;
int globalVar = 10; // 데이터 영역: 전역 변수
void function(int param) { // 코드 영역: function 함수의 코드
static int staticVar = 5; // 데이터 영역: 정적 변수
int localVar = 20; // 스택 영역: 지역 변수
}
class DynamicObject {
public:
DynamicObject() {
cout << "DynamicObject 생성" << endl;
}
~DynamicObject() {
cout << "DynamicObject " << endl;
}
};
int main() {
int mainLocalVar = 30; // 스택 영역: main 함수의 지역 변수
function(mainLocalVar); // 스택 영역: function의 매개변수 'param'
DynamicObject* dynamicObj = new DynamicObject(); // 힙 영역: 동적으로 할당된 객체
delete dynamicObj; // 힙 영역의 동적으로 할당된 객체 해제
return 0;
}
이런 느낌이다.
힙 메모리 해제에 관하여
힙 메모리 관리는 프로그램의 성능과 안전성에 매우 중요한 요소이다.
프로그램이 종료될 때 운영 체제는 프로세스에 할당된 모든 리소스와 메모리를 회수하기 때문에 프로그램 실행 중에 명시적으로 해제하지 않은 메모리도 프로그램 종료 시 운영 체제에 의해 자동으로 해제된다.
하지만 프로그램이 실행되는 동안 메모리 사용량이 증가하는 메모리 누수, 성능 저하가 발생할 수 있기 때문에, 최적의 성능을 유지하기 위해 적절한 시점에 메모리를 해제하는 것이 필수적이다. 그럼 어떻게 언제 해제할까?
1. 더 이상 사용하지 않을 때
2. 소유권과 책임이 명확한 구조에서
: 객체나 데이터에 대한 소유자가 메모리 할당과 해제의 책임을 지도록 한다. 예를 들어, 객체를 생성하고 관리하는 클래스나 모듈이 있다면, 해당 클래스나 모듈이 객체의 생명주기를 관리하며 필요 없어진 객체를 해제해야 함
3. 자원 관리자나 스마트 포인터를 사용할 때
: C++에서는 RAII(Resource Acquisition Is Initialization) 패턴을 사용하여 자원(메모리 포함)을 관리하는 것이 일반적입니다. 스마트 포인터(std::unique_ptr, std::shared_ptr)를 사용하면, 객체의 참조가 더 이상 필요하지 않게 되면 자동으로 메모리를 해제할 수 있습니다. 이 방법은 메모리 관리를 자동화하고 누수를 방지하는 데 매우 유용하다.
4. 프로그램의 논리적 단계나 특정 지점에서
: 프로그램이 특정 논리적 단계나 작업을 완료했을 때 메모리를 해제하는 것도 좋은 방법이. 예를 들어, 게임에서 한 레벨을 완료한 후 또는 대규모 데이터 처리 작업이 끝난 후에는 더 이상 필요하지 않은 데이터를 해제할 수 있다.
스마트 포인터
C++에서는 std::unique_ptr, std::shared_ptr, std::weak_ptr 등 여러 종류의 스마트 포인터를 제공한다.
#include <iostream>
#include <memory> // 스마트 포인터를 위한 헤더 파일
class MyClass {
public:
MyClass() {
std::cout << "MyClass 생성자 호출" << std::endl;
}
~MyClass() {
std::cout << "MyClass 파괴자 호출" << std::endl;
}
void myFunction() {
std::cout << "MyClass의 myFunction 호출" << std::endl;
}
};
int main() {
std::unique_ptr<MyClass> myObject = std::make_unique<MyClass>();
myObject->myFunction();
// myObject가 범위를 벗어날 때 자동으로 메모리 해제
return 0;
}
이 예제에서 SampleClass의 인스턴스가 생성될 때 동적으로 메모리가 할당되고, 인스턴스가 소멸될 때 파괴자가 호출되어 동적으로 할당된 메모리가 해제된다.
'개발 > C++' 카테고리의 다른 글
씹어먹는 C++ 공부하기 (9~) (0) | 2024.08.04 |
---|---|
씹어먹는 C++ 공부하기 (0) | 2024.05.16 |
[OS/ C++] 동기화를 위한 전략: 스핀락(spinlick), 뮤택스(mutex), 세마포(semaphore) (0) | 2024.02.08 |
[C++/STL Container] Vector, List, Array에 대해 (1) | 2024.02.03 |
[C++/STL Container] map, set에 대해 (3) | 2024.02.03 |