Post

박싱과 언박싱(Boxing and Unboxing) - C++/C#/CS 기초

박싱과 언박싱(Boxing and Unboxing)

📌 학습 목표


📌 개념 정리

  • 박싱(Boxing): 값 타입(struct, int 등)을 참조 타입(object, System.ValueType)으로 변환하는 과정
  • 언박싱(Unboxing): 참조 타입에 담긴 값을 다시 원래 값 타입으로 꺼내는 과정
  • 힙 할당과 복사 비용이 수반되므로 성능 저하 원인이 될 수 있다.
1
2
3
int n = 123;
object obj = n;      // 박싱: 값 타입 → object
int m = (int)obj;    // 언박싱: object → 값 타입

📌 동작 원리

  • 박싱 시: 새로운 힙 객체를 생성하고, 값 타입의 데이터를 그 안에 복사
  • 언박싱 시: 힙 객체의 내용을 값 타입 변수에 다시 복사
1
스택 (값 타입) → 힙에 object 생성 → 복사 저장 → 참조 반환

📌 성능 비용

  • 매번 힙에 객체 생성 + GC 부담
  • 언박싱은 형변환 + 복사 과정이 필요
  • 반복문/핫패스에서 사용 시 심각한 성능 저하

면접 포인트: “박싱/언박싱이 왜 문제가 될까?” → 불필요한 힙 할당과 GC 부담 때문이다.


📌 박싱/언박싱 회피법

  1. 제네릭(Generic) 사용
1
2
3
4
5
6
7
8
9
// 박싱 발생
ArrayList list = new ArrayList();
list.Add(1);           // int → object (박싱)
int x = (int)list[0];  // 언박싱

// 무박싱
List<int> list2 = new List<int>();
list2.Add(1);          // int 그대로 저장
int y = list2[0];      // 언박싱 없음
  1. 인터페이스 대신 제네릭 제약 사용
    1
    2
    3
    4
    5
    6
    
    int Sum<T>(List<T> data) where T : struct
    {
     int sum = 0;
     foreach (var v in data) sum += Convert.ToInt32(v);
     return sum;
    }
    
  2. Span<T>, Memory<T> 사용 (고급)**

📌 C++과의 비교

  • C++에는 박싱/언박싱 개념이 없음 (값 타입/참조 타입 구분이 다름)
  • 대신 RAII스마트 포인터로 메모리 관리
  • C#의 박싱/언박싱은 런타임 비용이므로 반드시 회피 전략 필요

📌 자주 묻는 질문

1) 박싱은 언제 발생하나요?
→ 값 타입이 object나 인터페이스로 변환될 때

2) 언박싱은 왜 비용이 큰가요?
형변환 검사 + 값 복사 과정이 필요하기 때문

3) 어떻게 피할 수 있나요?
→ **제네릭 사용, Span, 캐싱** 등을 통해


📌 치트시트

  • 박싱: 값 타입 → 참조 타입(object) 변환
  • 언박싱: 참조 타입(object) → 값 타입 변환
  • 비용: 힙 할당, GC 부담, 값 복사
  • 회피: 제네릭, Span, Memory

This post is licensed under CC BY 4.0 by the author.