본문 바로가기
우아한 코딩

boxing과 unboxing의 문제와 최소화 방안

by 피크인사이트 2024. 3. 27.
반응형

안녕하세요!

오늘은 프로그래밍에서 자주 발생하는 성능 문제 중 하나인 "boxing과 unboxing"에 대해 이야기해보려고 합니다.

이 용어가 익숙하지 않을 수 있지만, 함께 알아가면서 어떻게 이를 최소화할 수 있는지 알아보도록 하겠습니다.

 

<글 순서>

1. boxing과 unboxing이 뭐죠?

2. boxing과 unboxing이 어떤 문제를 일으키나요?

3. 어떻게 boxing과 unboxing을 최소화할 수 있나요?

boxing과 unboxing

1. boxing과 unboxing이 뭐죠?

여러분이 자주 사용하는 데이터 형식 중에는 값 형식과 참조 형식이 있습니다.

값 형식은 데이터를 스택에 저장하고, 참조 형식은 힙에 저장합니다.

그런데 때로는 값 형식을 참조 형식으로 변환하거나 반대로 참조 형식을 값 형식으로 변환해야 할 때가 있습니다.

이것이 바로 boxing과 unboxing입니다.

 

예시로 설명하면, 

int number = 42; // int는 값 형식입니다.
object boxedNumber = number; // 이제 number는 참조 형식인 object로 변환되었습니다. 
```

 

위에서는 정수형 변수인 `number`를 만들었습니다.

이 변수는 값 형식으로 스택에 저장됩니다.

그리고 `object`라는 참조 형식으로 `boxedNumber`라는 변수를 만들고, 거기에 `number`를 대입했습니다.

이때 `number`는 참조 형식으로 변환되어 힙에 저장됩니다.

이 과정이 바로 boxing입니다.

이러한 변환 과정에서는 값을 감싸고 있는 object 또는 다른 참조 형식으로 데이터를 복사하는 작업이 필요하며,

이로 인해 추가적인 메모리 할당과 해제 작업이 발생합니다.

이것이 바로 boxing과 unboxing이 메모리와 성능에 영향을 미치는 이유입니다.

 

2. boxing과 unboxing이 어떤 문제를 일으키나요?

boxing과 unboxing은 성능 문제를 야기할 수 있습니다.

이 작업들은 값 형식과 참조 형식 간의 데이터 변환을 수행하기 때문에 추가적인 메모리 할당과 해제 작업이 필요합니다.

특히 반복적으로 boxing과 unboxing을 수행하면 메모리 할당 및 해제의 빈번한 발생으로 인해 성능이 저하될 수 있습니다.

 

예를 들어, 다음과 같은 코드를 생각해 보세요

myList = new List();
for (int i = 0; i < 1000000; i++) { 
   myList.Add(i); // boxing 발생
   } 
   foreach (object item in myList) { 
      int value = (int)item; // unboxing 발생 
   }
```

위의 예시에서는 백만 개의 정수를 object 형식의 리스트에 추가하고, 이후에는 다시 그 값을 int 형식으로 변환하는 작업을 수행합니다. 이 과정에서는 백만 번의 boxing과 unboxing이 발생하며, 이는 성능에 부담을 줄 수 있습니다.

 

3. 어떻게 boxing과 unboxing을 최소화할 수 있나요?

boxing과 unboxing을 최소화하기 위해서는 몇 가지 방법이 있습니다.

1) 제네릭(Generic) 사용

제네릭을 사용하면 값 형식과 참조 형식 간의 변환을 피할 수 있습니다.

제네릭을 사용하면 컴파일 시간에 형식이 결정되므로 boxing과 unboxing이 발생하지 않습니다.

 // 제네릭을 사용하지 않은 경우
    ArrayList list = new ArrayList();
    list.Add(42); // boxing 발생
    int value = (int)list[0]; // unboxing 발생


    // 제네릭을 사용한 경우
    List<int> genericList = new List<int>();
    genericList.Add(42); // boxing이 발생하지 않음
    int genericValue = genericList[0]; // unboxing이 발생하지 않음
    ```

 

2) 값 형식 사용

값 형식을 사용하면 참조 형식과 달리 스택에 데이터가 저장되므로 boxing과 unboxing이 발생하지 않습니다.

따라서 값 형식을 사용하여 데이터를 다루는 것이 성능 향상에 도움이 됩니다.

// 값 형식 사용
    int value = 42; // boxing이 발생하지 않음

// 참조 형식 사용 (박싱이 발생함)
    object boxedValue = 42; // boxing 발생
    ```

 

3) 대체 방법 고려

boxing과 unboxing을 최소화하기 위해 대체 방법을 고려할 수도 있습니다.

예를 들어, object 대신에 값 형식을 사용할 수 있는 경우라면 그러한 방법을 선택하는 것이 좋습니다.

 // 값 형식을 사용하는 대안
    struct MyStruct
    {
        public int Value { get; set; }
    }

 // boxing이 발생하지 않음
    MyStruct myStruct = new MyStruct { Value = 42 };
    ```

 

이러한 방법들을 통해 boxing과 unboxing을 최소화하여 성능을 향상시킬 수 있습니다.


 

마무리

지금까지 이렇게 boxing과 unboxing에 대해 알아보았습니다.

이러한 작업은 성능에 영향을 미칠 수 있으며, 특히 반복적으로 수행되면 성능 문제를 야기할 수 있습니다.

하지만 우리는 제네릭을 사용하거나 값 형식을 활용하여 boxing과 unboxing을 최소화할 수 있습니다.

또한 대체 방법을 고려하여 최적화하는 방법도 살펴보았습니다.

 

좋은 코드는 성능을 고려하여 작성되어야 합니다.

앞으로도 더욱 효율적인 코드를 작성할 수 있도록 함께 공부하고 발전해 나가길 기대합니다.

반응형