15. 값 형식과 참조 형식 (Value Type & Reference Type)
메모리(memory) 구조 이해하기
C#에서는 데이터를 저장하는 방식에 따라 **값 형식(Value Type)**과 **참조 형식(Reference Type)**으로 나뉩니다.
Stack과 Heap
Stack (스택)
- Last In First Out (LIFO): 마지막에 들어온 것이 먼저 나감
- 값 형식 데이터가 저장되는 곳
- 빠른 접근 속도
- 작은 크기의 데이터에 적합
Heap (힙)
- 참조 형식 데이터가 저장되는 곳
- 동적으로 크기가 변할 수 있는 데이터
- 메모리(memory) 주소(참조)를 통해 접근
값 형식 (Value Type)
값 형식은 Stack에 저장되며, 데이터(값)를 직접 저장하는 방식입니다.
값 형식의 특징
- 데이터를 직접 복사
- 변수(variable)에 값을 할당하면 값 자체가 복사됨
- 한 변수(variable)를 변경해도 다른 변수(variable)에 영향 없음
값 형식 예시
int a = 5;
int b = a; // b에 a의 값(5)이 복사됨
b = 10; // b만 10으로 변경
Debug.Log(a); // 5 출력 (a는 변경되지 않음)
Debug.Log(b); // 10 출력
Unity에서 값 형식
Vector3(구조체(struct))int,float,bool등 기본 타입(type)- 구조체(struct)
Vector3 position1 = new Vector3(1, 2, 3);
Vector3 position2 = position1; // 값이 복사됨
position2.x = 10; // position2만 변경됨
// position1은 여전히 (1, 2, 3)
참조 형식 (Reference Type)
참조 형식은 Heap에 저장되며, 메모리(memory) 주소(참조)를 통해 접근하는 방식입니다.
참조 형식의 특징
- 메모리(memory) 주소를 저장
- 변수(variable)에 할당하면 같은 메모리(memory) 주소를 참조
- 한 변수(variable)를 변경하면 다른 변수(variable)도 영향받음
참조 형식 예시
int[] myArray = { 1, 2 };
int[] myArray2 = myArray; // 같은 메모리 주소를 참조
myArray2[1] = 7; // myArray2를 변경
Debug.Log(myArray[1]); // 7 출력 (myArray도 변경됨!)
Debug.Log(myArray2[1]); // 7 출력
이유: 두 배열(array)이 같은 메모리(memory) 주소를 바라보고 있기 때문입니다.
Unity에서 참조 형식
GameObject(클래스(class))string- 배열 (
int[],string[]) - 리스트 (
List<T>) - 클래스(class)
GameObject obj1 = new GameObject("Player");
GameObject obj2 = obj1; // 같은 객체를 참조
obj2.name = "Enemy"; // obj2의 이름 변경
// obj1.name도 "Enemy"로 변경됨!
new 키워드의 차이
값 형식에서의 new
Vector3 pos = new Vector3(1, 2, 3);
- Stack에 값을 생성
- 단순히 초기값을 설정하는 역할
참조 형식에서의 new
GameObject obj = new GameObject();
- Heap에 객체(object)를 생성
- 메모리(memory) 할당과 초기화를 수행
값 형식 vs 참조 형식 비교
| 특징 | 값 형식 (Value Type) | 참조 형식 (Reference Type) |
|---|---|---|
| 저장 위치 | Stack | Heap |
| 저장 내용 | 값 자체 | 메모리(memory) 주소 (참조) |
| 복사 방식 | 값 복사 | 참조 복사 |
| 변경 영향 | 독립적 | 공유됨 |
| 예시 | int, Vector3 |
GameObject, string[] |
실전 활용 예시
값 형식 활용
// 플레이어 위치 저장
Vector3 playerPos = new Vector3(0, 0, 0);
Vector3 savedPos = playerPos; // 값 복사
playerPos.x = 10; // playerPos만 변경
// savedPos는 여전히 (0, 0, 0)
참조 형식 활용
// 여러 스크립트가 같은 리스트 공유
List<int> scores = new List<int>() { 100, 200 };
List<int> highScores = scores; // 같은 리스트 참조
highScores.Add(300); // highScores에 추가
// scores에도 300이 추가됨!
주의사항
- 참조 형식은 메모리(memory) 주소를 공유하므로, 한 곳에서 변경하면 다른 곳도 영향받음
- 값 형식은 값 자체를 복사하므로, 각각 독립적으로 동작
- Unity에서
GameObject는 참조 형식이므로 주의해서 사용