본문 바로가기
C#

[C#] 박싱(Boxing)과 언박싱(Unboxing)

by ifhead 2022. 9. 10.
반응형

박싱과 언박싱을 알아야 하는 이유가 개념 자체보다 중요합니다.

결국, 성능 때문에 우리는 박싱과 언박싱에 주목해야 합니다.

여러분은 이미 박싱과 언박싱을 많이 사용하고 있고, 개념도 어렵지 않습니다.

 

박싱/언박싱 간단 설명

박싱은 값 타입을 참조 타입으로 바꾸는 행위입니다. 언박싱은 반대입니다.

박싱이든 언박싱이든 스택 메모리와 힙 메모리를 오가고 복제하는 과정에서 오버헤드가 발생합니다.

int i = 1; // int는 값 타입, object는 참조 타입 
object o = i;   // boxing
int j = (int)o; // unboxing

 

문제 상황

  • 클래스는 참조 타입입니다. 참조 타입은 인스턴스화 시 힙 메모리에 저장됩니다.
  • 구조체는 값 타입입니다. 선언 시 스택 메모리에 저장됩니다.
  • 박싱-언박싱 과정에서 힙에 낭비되는 메모리 공간이 문제입니다.
  • MSDN에 의하면 박싱은 참조에 단순 할당(힙에 할당)하는 작업보다 20배 오래 걸리고, 언박싱 시 4배정도 시간이 소요됩니다.
  • 배열(Array)과 컬렉션(Collection)은 코드가 복잡해질 수록 더 많은 시간이 걸릴수 있습니다. 
  1. 박스형 값 유형 객체는 더 많은 메모리를 차지합니다.
  2. 박스형 값 유형 개체는 추가 읽기가 필요합니다.
  3. 박싱 및 언박싱 작업은 CPU와 시간을 소모합니다.
  4. 캐스팅이 필요하고 비용이 많이 들 수 있음

 

해결법

  • 제네릭을 사용해서 박싱과 언박싱을 최소화합니다. 
  • 일반화 컬렉션(Generalization Collection)을 이용합니다.

 

박싱 및 언박싱을 방지하는 방법

  1. int, double, float 등과 같은 숫자 데이터 유형의 ToString 메소드를 사용하십시오 .
  2. for 루프를 사용하여 값 유형 배열 또는 목록을 열거합니다(foreach 루프 또는 LINQ 쿼리를 사용하지 않음).
  3. for 루프를 사용하여 문자열의 문자를 열거합니다(foreach 루프 또는 LINQ 쿼리를 사용하지 않음).
  4. 고유한 값 유형을 정의하는 경우 기본 개체 메서드의 구현을 재정의합니다 .
  5. 불가피한 경우가 아니면 개체에 값 유형 인스턴스를 할당하지 마십시오.
  6. ArrList & HashTable 대신 일반 List<>, Dictionary<>(외 다수)를 사용하십시오 .
  7. Nullable<> 값 유형 사용(예: int?, float? 등)
  8. string.Format(SrtingBuilder.AppendFormat) 또는 'params object[]'를 사용하는 유사한 API를 사용할 때 'ToString()' 메서드를 호출하여 값 유형 개체를 전달합니다.

 

리팩토링으로 제거

  1. 암시적 복싱(예: object num = 1; )
  2. 값 타입에 대한 foreach 사용
  3. 값 타입 컬렉션에 대한 LINQ 쿼리
  4. 값 타입으로 캐스팅
  5. 스트링을 스트링빌더로 대체

반응형

댓글