다음을 통해 공유


값 형식 및 참조 형식(Visual C# Express)

업데이트: 2007년 11월

지금까지 사용하던 프로그래밍 언어와 달리 C#에는 값 형식과 참조 형식이라는 두 가지 데이터 형식이 있습니다. 응용 프로그램의 성능이 중요하거나 C#의 데이터 및 메모리 관리 방식에 관심이 있는 경우에는 두 형식의 차이점을 알아야 합니다.

기본 제공 데이터 형식 중 하나 또는 사용자 정의 구조체를 사용하여 선언된 변수는 값 형식입니다. string 데이터 형식은 예외적으로 참조 형식입니다.

값 형식은 스택에 할당된 메모리에 내용을 저장합니다. 예를 들어 아래 경우에는 스택이라는 메모리 영역에 값 42가 저장됩니다.

int x = 42;

x 변수가 정의된 메서드의 실행이 종료되어 변수가 범위를 벗어나면 값이 스택에서 삭제됩니다.

스택을 사용하면 효율적이지만 값 형식의 수명이 제한되므로 서로 다른 클래스 간에 데이터를 공유하는 데는 적합하지 않습니다.

반대로 클래스 또는 배열의 인스턴스와 같은 참조 형식은 힙이라는 다른 메모리 영역에 할당됩니다. 다음 예제에서는 배열을 구성하는 10개의 정수에 필요한 공간이 힙에 할당됩니다.

int[] numbers = new int[10];

이 메모리는 메서드가 종료되어도 힙에 반환되지 않으며, C#의 가비지 수집 시스템에서 이 메모리가 더 이상 필요하지 않다고 판단할 때에만 회수됩니다. 참조 형식을 선언하면 오버헤드가 커지지만 참조 형식은 다른 클래스에서 액세스할 수 있다는 장점이 있습니다.

Boxing 및 Unboxing

Boxing은 값 형식을 참조 형식으로 변환하는 프로세스를 가리킵니다. 변수를 boxing하면 힙의 새 복사본을 가리키는 참조 변수가 만들어집니다. 참조 변수는 개체이므로 모든 개체가 상속하는 모든 메서드(예: ToString())를 사용할 수 있습니다. 다음 코드에서는 이 방법을 보여 줍니다.

int i = 67;                              // i is a value type
object o = i;                            // i is boxed
System.Console.WriteLine(i.ToString());  // i is boxed

ArrayList를 사용하여 정수를 저장하는 것과 같이 개체와 함께 사용하도록 디자인된 클래스를 사용하면 unboxing이 수행됩니다. 정수를 ArrayList에 저장하면 정수가 boxing됩니다. 또한 정수를 검색할 때는 unboxing되어야 합니다.

System.Collections.ArrayList list = 
    new System.Collections.ArrayList();  // list is a reference type
int n = 67;                              // n is a value type
list.Add(n);                             // n is boxed
n = (int)list[0];                        // list[0] is unboxed

성능 문제

이제 좀 더 세부적인 면을 살펴봅니다. 데이터를 값 형식 매개 변수로 메서드에 전달하면 스택에 각 매개 변수의 복사본이 만들어집니다. 따라서 해당 매개 변수가 많은 요소가 있는 사용자 정의 구조체와 같은 큰 데이터 형식이거나 메서드가 여러 번 실행되는 경우 성능에 영향을 줄 수 있습니다.

이런 경우에는 ref 키워드를 사용하여 해당 형식에 대한 참조를 전달하는 것이 좋습니다. 이 방법은 C++에서 변수에 대한 포인터를 함수에 전달하는 방법과 동일합니다. C++ 버전과 마찬가지로 메서드에서 변수의 내용을 변경할 수 있으며 이는 일부 경우에 안전하지 않을 수 있습니다. 따라서 프로그래머는 보안과 성능 간의 관계를 고려하여 가장 적절한 형식을 결정해야 합니다.

int AddTen(int number)  // parameter is passed by value
{
    return number + 10;
}
void AddTen(ref int number)  // parameter is passed by reference
{
    number += 10;
}

out 키워드는 ref 키워드와 비슷하지만, 해당 메서드가 매개 변수에 값을 할당해야 하며 그렇지 않으면 컴파일 오류가 발생함을 컴파일러에 알려 준다는 점이 다릅니다.

void SetToTen(out int number)
{
    // If this line is not present, the code will not compile.
    number = 10;
}

참고 항목

개념

C# 언어 입문

기본 제공 데이터 형식(Visual C# Express)

배열 및 컬렉션(Visual C# Express)

참조

값 형식(C# 참조)

참조 형식(C# 참조)

Boxing 및 Unboxing(C# 프로그래밍 가이드)