C#에는 2가지 데이터 형식이 존재한다.
중요하다고 볼 수 있는 점은 대입 연산자 과정에 있다.
더욱이 복사 연산이 될 때다.
이 차이점은 이들 형식이 복사되는 방식에 따라 나뉘게 된다.
값형식의 데이터는 항상 값으로 복사되지만, 참조형식 데이터는 항상 참조로 복사된다.
알아보자
참고로
값 형식은 얕은 복사(Shallow)
참조 형식은 깊은 복사(Deep)
기본 제공 데이터 형식 중 하나 또는 사용자 정의 구조체를 사용하여 선언된 변수는 값 형식을 가진다.
** 예외적으로 string 타입은 참조 형식이다.
기본 제공 타입은
이정도?
bool, char, byte, decimal, double, enum, float, int long, short, sbyte, struct, uint, ulong, ushort
**Stack
값 형식은 스택에 할당된 메모리에 데이터를 저장한다.
다시 말해서 해당 변수가 정의된 메서드의 실행이 종료되어 변수가 범위를 벗어나면 값이 스택에서 삭제된다.
** 또는 블록을 벗어남
당연히 스택을 사용하면 메모리 해제가 자유롭지만 해당 생명주기(life cycle)에 제약이 생긴다.
즉, 서로 다른 클래스 간에 데이터를 공유하기엔 적절하지 못한 방법이다.
**Heap
클래스 또는 배열의 인스턴스와 같은 참조 형식은 힙이라는 다른 메모리 영역에 할당된다.
타입을 말하자면 이정도?
class, interface, delegate, object, string
예를 들어서 배열을 만든다면
int[] arr = new int[10001];
이런 식으로 new 같이 메모리를 할당받는 느낌?
이 메모리는 메서드가 종료되어도 자동으로 반환되지 않는다.
C#의 Garbage Collection 시스템에서 세대를 거쳐 참조를 하지 않게 되면 메모리로 다시 회수된다.
메모리가 힙에 남는 것이 꼭 단점만은 아니다.
참조 형식으로 선언하면 오버헤드가 커지지만 참조 형식은 다른 클래스에서 접근할 수 있다.
그렇다면 박싱 언박싱이 어디서 나오느냐?
바로 여기서 나온다.
Boxing은 값 형식을 참조 형식으로 변환하는 과정을 말한다.
변수를 boxing하면 힙의 새 복사본을 가리키는 참조 변수가 만들어진다.
-> C++의 참조변수와 비슷하다.
예를 들면 참조 변수는 개체이므로 모든 개체가 상속하는 모든 메서드(예: 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된다.
다시 ArrayList에서 정수를 검색할 때는 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
C++에도 있는 방식이다.
다만 따로 박싱 언박싱이라는 용어는 쓰지 않는 듯하다.
C# 에서 박싱, 언박싱이 중요한 이유는 참조형식은 힙에 저장되기 때문이다.
즉, 우리가 직접 해제하는 것이 아닌 Garbage Collection에게 맡기기 때문에
C++과는 다르게 오버헤드가 크게 생길 수 있다.
MSDN의 문서에서 보자면
This can take up to 20 times longer than a simple reference assignment.
When unboxing, the casting process can take four times as long as an assignment.
'Game Development, 게임개발 > 개발' 카테고리의 다른 글
Convert 그리고 Parse의 문화권 문제 [C#] (0) | 2022.05.22 |
---|---|
RectTransform과 Transform의 이해 (0) | 2022.04.17 |
C#에서의 Func, Action [Unity] (0) | 2022.04.04 |
아이템 인벤토리 확장 기능 구현하기 (0) | 2022.03.20 |
휴대용 디바이스에서의 렌더링,Redering 조절로 배터리 소모 낮추기(OnDemandRendering) (0) | 2022.03.14 |