참고 자료
1) https://learn.microsoft.com/ko-kr/dotnet/csharp/programming-guide/types/boxing-and-unboxing
2) https://learn.microsoft.com/ko-kr/dotnet/api/system.object?view=net-7.0
메모리 상 데이터 값이 어떻게 저장되는 지에 따라 두가지 Type으로 나뉜다.
https://learn.microsoft.com/ko-kr/dotnet/csharp/language-reference/keywords/reference-types
데이터(개체)에 대한 참조를 저장해 놓은 형식이다. 참조를 저장하기 때문에 여러 변수가 같은 데이터(개체)를 참조할 수 있다. 즉, 하나의 수정이 여러 변수에 영향을 미칠 수 있다.
Ex) class, interface, object, string, ...
https://learn.microsoft.com/ko-kr/dotnet/csharp/language-reference/builtin-types/value-types
실제 데이터 값을 저장하는 형식이다. 데이터의 자체 사본이 들어 있기에 하나의 수정이 다른 변수들에게 영향을 미치지 않는다.
Ex) struct, bool, int, ...
.net에서 object는 모든 형식에 대한 부모로 동작하고 있다. (즉, 모든 클래스들은 object를 상속받고 있다.)
박싱은 value type을 object type (reference type)으로 변환하는 것이다. 즉, stack 메모리에 저장된 값을 힙 메모리로 복사한다고 이해할 수 있다.
기존에 자식 클래스와 부모 클래스의 형변환을 생각해보면 자식(value type)에서 부모클래스(object type)로 형변환 할 때는 이미 부모 클래스에 대한 내용을 다 가지고 있기 때문에 크게 문제가 되지 않는다. 즉, 암시적 변환이 된다.
언박싱은 반대로 object type(reference type)을 value type으로 변환하는 과정으로 힙 메모리에서 빼서 다시 스택으로 저장하는 과정이라 볼 수 있다.
이 경우 반대로 부모 클래스(object type)에서 자식 클래스(value type)로 형변환을 하는 경우이다. 이때는 명시적 변환이 필요하다.
Unboxing은 다음의 과정을 거친다.
1) 지정한 value type을 boxing한 것인지 확인한다. (만약 이전의 value type과 호환되지 않으면 InvalidCastException이 일어난다.)
int i = 123;
object o = i;
int j = (short) o; // InvalidCastException
2) 인스턴스의 값을 value type 변수에 복사한다.
다음 코드는 박싱과 언박싱이 일어나는 모습을 보여준다.
int i = 123; // 1)
object o = i; // 2) boxing
int j = (int) o; // 3) unboxing
1) 먼저 value type의 i가 스택에 저장된다.
2) object가 참조 타입으로 동작하므로 boxing을 할 때 힙에 메모리가 할당되고 이에 대한 참조가 스택에 저장된다.
3) value type 변수에 값을 복사하면서 (unboxing) j가 스택에 저장된다.
형식이 다른 여러 변수를 한 번에 처리할 때 주로 사용된다.
예를 들어 리스트나 배열같은데에 여러 형식의 값을 담고 싶을 수 있는데 int와 같이 한 형식으로 정의하면 다른 형식을 담을 수 없다. 이럴 때 object로 정의해 다양한 형식을 담아두고 (boxing) 내부의 값을 사용할 때 unboxing을 한다.
List<int> intList = new List<int>() {1, 2};
List<object> objectList = new List<object>() {1, "string"};
C#의 일부 함수에서도 boxing과 unboxing이 사용되고 있다. 그 중 C#의 Concat 함수를 살펴보자. 내부적으로 다양한 형식에 대해 오버로딩하여 구현되어 있다.
본 코드에서는 3개의 object 매개 변수를 받고 있는 Concat 함수인데 여기서 42와 true는 boxing 된다.
Console.WriteLine(String.Concat("Answer", 42, true));
❗ boxing과 unboxing은 성능적인 측면에서 선호되지 않는다.
위에 코드에서 메모리 상 boxing과 unboxing의 단점을 볼 수 있었다. object가 참조 타입으로 동작하기에 내부적으로 힙에 메모리를 할당하고 다시 힙에서 빼서 스택에 저장하는 과정을 거친다.
(value type이 boxing되는 경우 완전히 새로운 개체를 생성하는데 이는 단순 reference type 할당과 비교해 20배나 오래 걸린다고 한다. 추가로 unboxing시 캐스팅하는 프로세스는 할당의 4배 정도 걸린다.)
이에 boxing과 unboxing 대신 다음을 고려해보는 것을 권장하고 있다.
다양한 형식에 대해 메소드를 오버로딩하여 작성해서 최대한 boxing과 unboxing의 사용을 줄이는 것이다.
간단히 말하면 인스턴스화 되기 전까지 형식 결정을 미루는 것이라고 볼 수 있다. 일반화를 사용하면 런타임 캐스팅 또는 boxing 작업 없이 단일 클래스를 작성할 수 있다.
I really like reading an article that can make men and women think. Also, thanks for allowing me to comment!
https://infocampus.co.in/ui-development-training-in-bangalore.html
https://infocampus.co.in/web-development-training-in-bangalore.html
https://infocampus.co.in/reactjs-training-in-marathahalli-bangalore.html
https://infocampus.co.in/mern-stack-training-in-bangalore.html
https://infocampus.co.in/javascript-jquery-training-in-bangalore.html
https://infocampus.co.in/data-structure-algorithms-training-in-bangalore.html
https://infocampus.co.in/angularjs-training-in-bangalore.html
https://infocampus.co.in/front-end-development-course-in-bangalore.html