Unity & C#

C# 박싱 / 언박싱 (Boxing/Unboxing), ArrayList

coucou3 2020. 8. 29. 14:27
반응형

C#에서 모든 데이터 형식은 object를 상속 받는다.

 

1. Boxing

Boxing은 Value Type(int, float, char, bool, struct, ...)의 데이터를  Reference Type(object, string, class, ...)으로 변환하는 프로세스이다.

int i = 1;
object o = i;    // 암시적 Boxing

 

값 형식의 데이터는 메모리의 스택 영역에 할당되는데, Boxing을 통해 참조 타입인 object로 변환되면서 힙 영역에 복사된다.

Boxing (출처 : MSDN)

 

# Boxing.cs

public class Boxing : MonoBehaviour
{
    void Start()
    {
        int i = 1;
        object o = i;

        i = 2;
        
        Debug.Log("i : " + i);
        Debug.Log("o : " + o);
    }
}

i를 object o로 boxing하면 힙 영역에 i의 값을 복사한다.

i와 o는 서로 다른 메모리 위치를 사용하기 때문에, 위 결과 다른 값을 갖게 된다.

 

# Boxing2.cs

public class Boxing2 : MonoBehaviour
{
    void Start()
    {
        int a = 1;
        int b = a;
        object oa = a;
        object ob = b;
        Debug.Log("a == b : " + (a == b));
        Debug.Log("oa == ob : " + (oa == ob));
    }
}

object는 Reference Type으로 힙 영역에 할당된 메모리의 주소를 갖고있다.

Reference Type에 대한 '==' 연산자는 참조에 대한 비교로, oa와 ob는 다른 주소를 갖고 있으므로 False를 return한다. (메모리 위치의 값과는 상관없이)

 

 

2. Unboxing

Unboxing은 반대로 object 형식을 Value Type으로 변환하는 프로세스다.

int i = 1;
object o = i;    // Boxing

o = 2;
int j = (int)o;    // Unboxing

 

참조 타입인 Object가 값 형식 데이터로 Unboxing된다. 이때 Object가 참조하고 있는 메모리의 값을 스택 영역에 복사한다.

Unboxing (출처 : MSDN)

 

Unboxing은 Boxing된 데이터의 원래 타입으로 명시적인 형변환만 가능하다.

MSDN에 따르면 다음과 같은 연산 과정을 겪는다.

•개체 인스턴스가 지정한 값 형식을 boxing한 값인지 확인합니다.
•인스턴스의 값을 값 형식 변수에 복사합니다.

 

null에 대한 unboxing 시도는 NullReferenceException, 원래 값 형식과 다른 타입에 대한 참조는 InvalidCastException이 발생한다.

 

 

 

3. ArrayList

ArrayList는 복잡자료형 클래스로, 여러 타입의 데이터를 담을 수 있다.

Add 메서드는 object를 매개변수로 받는다.

public virtual int Add (object value);
ArrayList al = new ArrayList();
al.Add(1);
al.Add(0.1f);
al.Add("string");

 

파이썬의 List나 Dictionary처럼 자료형에 구애받지 않고 편리하게 사용할 수 있을 듯하나 지금은 권장되지 않는 방법이다.

MSDN의 ArrayList 설명에 다음과 같이 명시 되어있다.

⚠️ 중요

새 개발에는 클래스를 사용 하지 않는 것이 좋습니다 ArrayList . 대신 제네릭 클래스를 사용하는 것이 좋습니다 List<T>. ArrayList클래스는 개체의 유형이 다른 컬렉션을 포함 하도록 디자인 되었습니다. 그러나 항상 최상의 성능을 제공 하는 것은 아닙니다. 대신, 다음을 수행하는 것이 좋습니다.

•다른 유형의 개체 컬렉션의 경우 List<Object> (c #의 경우) 또는 List(Of Object) (Visual Basic)를 사용 합니다.

•개체의 유형이 같은 컬렉션의 경우 클래스를 사용 List<T> 합니다. 이러한 클래스의 상대적인 성능에 대 한 설명은 참조 항목의 성능 고려 사항 을 참조 하세요 List<T> . 제네릭이 아닌 컬렉션 형식 대신 제네릭 사용에 대 한 일반 정보는 GitHub에서 제네릭이 아닌 컬렉션을 사용 하지 않아야 합니다 .를 참조 하세요.

 

기본적으로 스택은 작고 빠르지만, 힙은 크고 느리다.

다시 말해 힙 영역에 메모리를 할당하는 것은 스택 영역을 사용하는 것보다 많은 비용이 소요된다. 또한 힙 영역에 할당된 메모리는 가비지 컬렉터가 따라 붙기 때문에 추가 비용도 발생한다.

 

ArrayList vs List<Object>

복잡자료형을 사용할 때 ArrayList 대신 Generic 클래스 List<object>를 사용하라고 되어있다.

두 방법 간 퍼포먼스 차이는 크게 없다.

다만 LINQ Extension Methods와 같이 Generic Class를 사용했을 경우 편리한 일이 많아 권장되는 것 같다.

 

참고1) MSDN Boxing  Unboxing(C# 프로그래밍 가이드) - https://docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/types/boxing-and-unboxing

참고2) IL2CPP 최적화 : 박싱(Boxing) 피하기 - https://blogs.unity3d.com/kr/2016/08/11/il2cpp-optimizations-avoid-boxing/

참고3) ArrayList vs List<object> - https://stackoverflow.com/questions/391088/arraylist-vs-listobject

반응형