본문 바로가기

Architecture for Software/.NET

C#의 Value Type과 Reference Type

여러 다른 언어들과 마찬가지로 C#에서도 효과적인 메모리 관리를 위하여 고유 데이터 타입을 정의해 두고 있습니다.

예를 들어 정수, 문자열, 부동 소수점, Boolean 등에 대한 타입들이 바로 그런 예입니다.

여기서 특이한 점은 C#에서는 데이터 타입을 "값 기반(Value based)"과 "참조 기반(Reference based)"로 구분해두고 있습니다.

중요한 점은 Value based Type의 경우 스택(Stack)에 값들을 할당하며, Reference Based Type의 경우 힙(Heap)에 값들을 할당한다는 점입니다.

만약 다음과 같은 코드가 존재한다면 Value Type일까요? 아니면 Reference Type일까요?

// Assign
int a = 2;
int b = 3;

// Swap Value
b = a;
a = 3;

// Print
Console.WriteLine("a = {0}, b = {1}", a, b);

상기 코드에서 a와 b에 할당된 값들은 모두 스택에 저장됩니다. 즉 Value Type입니다.
따라서 결과적으로 a는 3이란 값을 가지며 b는 모드 2란 값을 가지게 됩니다. 결과적으로 서로의 값은 하나의 스택이란 공간에서 각기 다른 주소를 가진 값으로 저장되어 있어 서로 영향을 받지 않습니다.

하지만 Reference Type의 경우는 다릅니다.

// Assign
Foo a = new Foo();
a.x = 10;
a.y = 20;

// Swap
Foo b = a;
b.x = 20;
b.y = 10;

// Print
Console.WriteLine("a.x = {0}, a.y = {1}, b.x = {2}, b.y = {3}", a.x, a.y, b.x, b.y);

결과적으로 a.x 는 20, a.y 는 10, b.x 는 20, b.y 는 10이 됩니다. 즉 a 객체와 b 객체 모두 같은 저장공간에 값을 저장하고 있으며, 같은 주소를 참조하고 있다는 것입니다.

이것이 Reference Type입니다. Reference Type의 가장 큰 특징은 Heap 공간에 데이터를 저장한다는 것입니다. 또한 Heap에 저장된 데이타 중 어느 곳에서도 참조하고 있지 않으면 주기적으로 무시무시한 가비지 컬렉터(Garbage Collector)에 의하여 Heap안에서 제거된다는 것입니다.

즉 참조 타입은 힙공간에 저장되며, 참조가 없는 경우에는 가비지 컬렉터에 의하여 삭제된다. 라는 특성을 가지고 있습니다.

여기서 한가지 더 알아야 할것이 얕은 복사(Swallow copy)라는 개념입니다. 하나의 객체를 다른 객체로 복사하였을 때 복사본이 원본에 대한 포인터를 가지고 있다는 말입니다. 즉 복사시 원본 메모리의 내역을 복사하여 새로운 메모리 공간에 데이타를 할당하지 않고 기존의 메모리 주소를 가리킬 수 있도록만 한다는 것입니다.

따라서 진정한 의미에서 복사는 아니며 단지 힙 공간을 효과적으로 사용하기 위한 메모리 관리 기법입니다.

이와 반대되는 개념이 깊은 복사(Deep copy)가 있는데, 이것이 힙안에 있는 메모리를 완전하게 새로 복사하여 다른 힙 공간안에 주소를 할당받아 복사하는 개념입니다.

따라서 Reference Type에는 Copy도 Swallow copy Deep copy존재한다는 것을 이해할 필요가 있습니다.