C#의 메모리 구조는 총 4가지의 영역으로 나뉘어져 있습니다.
1. 스택(Stack) - 값 형식이 저장되는 메모리 공간이며 메소드 호출에 필요한 메모리가 저장됨
2. 힙(Heap) - 참조 형식이 저장되는 메모리 공간이며 동적 할당된 메모리가 저장됨
3. 데이터 영역(Data Segment) - 초기화된 또는 초기화되지 않은 정적, 전역변수가 저장됨
4. 코드 영역(Code Segment) - 프로그램의 실행 코드가 저장됨
스택(Stack)
스택은 값 형식이 저장되는 메모리 공간이며 지역변수, 매개변수, 리턴값 같은 메소드를 호출하는데 필요한 메모리가 저장됩니다.
특징으로는 스택 메모리는 LIFO(후입선출) 구조로, 메모리 할당과 해제가 매우 빠릅니다. 또한 보통 고정된 작은 크기를 가지고 있습니다. 컴파일 시점에 크기가 결정됩니다.
더보기
(컴파일 시점은 프로그램의 컴파일러에 의해 번역되는 시점, 런타임 시점은 유니티 에디터에서 Play를 눌렀을 때의 시점. 코딩을 하다가 타입이 맞지 않는 경우가 컴파일 시점 에러, 값을 할당해주지 않아 널레퍼런스가 나는 것이 런타임 시점 에러이다.)
스택이 사용되는 주요 시점은 다음과 같습니다.
1. 지역 변수
- 메서드나 블록 안에서 선언된 지역 변수는 스택에 저장됩니다.
- 이러한 변수는 메서드나 블록이 끝나면 자동으로 해제되므로, 명시적인 메모리 관리가 필요하지 않습니다.
2. 메서드 호출
- 메서드가 호출될 때 스택 프레임이 생성됩니다. 이 프레임에는 메서드의 매개변수, 반환 주소, 지역 변수가 포함됩니다.
- 메서드가 호출될 때마다 새로운 스택 프레임이 추가되고, 메서드가 종료되면 해당 스택 프레임이 제거됩니다.
3. 값 형식(Value Types)
- int, float, bool과 같은 값 타입은 스택에 저장됩니다.
- 값 형식은 스택에서 할당 및 해제되며, 이는 힙 메모리보다 성능상 이점이 있습니다.
- 단, 값 형식이라도 참조 형식의 필드로 사용되면 힙에 저장됩니다.
- (예를들어 int 변수가 클래스 내부에 있는데 이 클래스를 동적 생성했을때, 이 클래스 내부에 있는 int 변수는 값 형식일지라도 힙에 저장되는 것)
4. 재귀 메서드
- 재귀적으로 메서드를 호출할 때, 각 재귀 호출은 새로운 스택 프레임을 사용합니다.
- 스택 오버플로우(Stack Overflow)는 너무 깊은 재귀 호출로 인해 스택 메모리가 초과될 때 발생합니다.
힙(Heap)
힙은 참조 형식이 저장되는 메모리 공간이며 동적할당으로 생성된 메모리가 저장됩니다.
일반적으로 스택보다 크며 동적 크기입니다. 런타임 시점에 크기가 결정됩니다.
힙의 메모리는 가비지 콜렉터(Garbage Collector)에 의해 관리됩니다.
힙이 사용되는 주요 시점은 다음과 같습니다
1. 참조 타입(Reference Types)
- 클래스, 배열, 델리게이트, 객체 등 참조 형식의 인스턴스는 힙에 할당됩니다.
- 참조 형식은 메모리 주소(참조)를 통해 접근되며, 해당 주소는 스택에 저장되지만 실제 데이터는 힙에 저장됩니다.
2. 큰 데이터
- 큰 데이터 구조(예: 큰 배열, 복잡한 객체 그래프)는 스택에 저장하기에는 너무 크므로 힙에 저장됩니다.
- 힙은 스택보다 메모리 공간이 크기 때문에 더 큰 메모리 블록을 저장할 수 있습니다.
3. 긴 생명주기를 가진 데이터
- 프로그램의 여러 부분에서 오랜 기간 동안 사용되는 객체는 힙에 저장됩니다.
- 예를 들어, 애플리케이션의 전체 실행 동안 유지되어야 하는 객체는 힙에 저장됩니다.
4. 객체 간의 데이터 공유
- 여러 객체가 동일한 데이터를 공유하거나 동일한 객체를 참조해야 하는 경우, 이 데이터는 힙에 저장됩니다.
- 힙에 저장된 객체의 참조는 스택을 통해 다른 객체에 전달될 수 있습니다.
5. 동적 메모리 할당
- 런타임 중에 메모리 크기가 결정되거나 변경될 수 있는 데이터 구조(예: 동적으로 크기가 변하는 리스트)는 힙에 할당됩니다.
- 예를 들어, List<T>, Dictionary<TKey, TValue>와 같은 컬렉션 클래스는 힙을 사용하여 동적으로 메모리를 할당합니다.
6. 클로저(Closures)
- 람다 표현식이나 익명 메서드에서 사용하는 외부 변수들은 힙에 저장될 수 있습니다.
- 클로저는 메서드가 종료된 후에도 변수에 대한 참조를 유지해야 하므로, 이들 변수는 힙에 저장됩니다.
값 형식과 참조 형식이 각 메모리에 저장되는 방식에 대해서는 아래 글 참고
힙 메모리와 스택 메모리의 비교
- 속도: 스택 메모리는 힙 메모리보다 할당 및 해제가 빠릅니다. 힙 메모리는 상대적으로 느립니다.
- 크기: 스택 메모리는 상대적으로 작은 크기를 가지며, 고정된 크기로 할당됩니다. 반면, 힙은 더 큰 메모리 공간을 사용할 수 있으며, 동적 크기로 할당됩니다.
- 메모리 관리: 스택 메모리는 자동으로 할당되고 해제되지만, 힙 메모리는 GC에 의해 관리되며, 수동으로 관리할 필요가 없습니다.
데이터 영역(Data Segment)
데이터 영역에는 정적 변수와 전역 변수가 저장됩니다. 초기화된 영역과 초기화되지 않은 영역으로 나뉩니다.
초기화된 영역 (Initialized Data Segment)
초기화된 영역에는 프로그램 시작 전에 초기화된 정적 변수 및 전역 변수가 저장됩니다.
public int InitValue = 0;
public static int StaticInitValue = 0;
초기화되지 않은 영역 (ninitialized Data Segment)
초기화되지 않은 영역에는 프로그램 시작 시 초기화되지 않은 정적 변수 및 전역 변수가 저장됩니다.
기본 값은 자동으로 0으로 초기화합니다.
public int InitValue;
public static int StaticInitValue;
코드 영역(Code Segment)
이 영역에는 프로그램의 실행 코드가 저장됩니다. 일반적으로 읽기 전용이며, 메모리 보호 기법에 의해 실행 중에 변경되지 않도록 되어 있습니다.
'C# 기초' 카테고리의 다른 글
[C#] 리플렉션 - Activator.CreateInstance (0) | 2024.04.21 |
---|---|
[C#] 배열, 리스트, 딕셔너리 (Array, List, Dictionary) (1) | 2023.12.11 |
[C#] delegate(델리게이트)와 event(이벤트) (0) | 2023.11.08 |
[C#] async와 await 키워드 그리고 코루틴(Coroutine)과의 차이 (0) | 2023.10.31 |
[C#][개념] 스레드와 동기/비동기 (0) | 2023.10.31 |