박싱이란 것은 Value type 객체를 Reference type객체로 바꾸는 것을 말하는데요.
C#에서는 모든 객체가 object로부터 상속됩니다.
int, float같은 Value type조차도 object로부터 상속받은 것처럼 사용할 수 있습니다.
이런것들을 주의하지 않고 코드를 짜게 될경우 의도치 않게 박싱이 일어나는 곳들이 생기게 되고 이것이 누적되면 무시할 수 없는 속도저하가 일어나게 됩니다.
아래의 예를 보시면, 리스트에 서로 다른 여러 종류의 type 값을 추가하는데 foreach문 안에서 item을 object로만 받아서 처리하고 있는것을 보실 수 있습니다.
class MyClass { public override string ToString() { return "다섯"; } static public void Sample() { ArrayList list = new ArrayList(); // 리스트에 아래처럼 여러가지 타입의 값을 추가해 넣어줍니다. // int형 float형 string형 등등..... list.Add(1); list.Add(1.5f); list.Add(‘3’); list.Add("four"); list.Add(new MyClass()); // 리스트에서 값을 꺼낼때 오직 object로 받아서 처리하고 있습니다. // 이런 경우 Value type을 Reference type으로 바꿔주면서 시간이 오래 걸리고 // 변환하면서 heap에 저장이 됩니다. // 시간도 오래 걸리고 가비지도 생기게 되겠네요. foreach (object item in list) { Debug.log(item.ToString()); } } }그래서 여러 type을 처리해야만 하는 경우가 아니라면 값의 type을 명시할 수 있는 Generic collection의 사용이 좋겠습니다.
Generic은 C++의 template과 비슷해서 C++의 STL container와 비슷하게 생겼습니다.
아래의 예제에서 잘 사용한 경우와 그렇지 않은 경우를 비교해서 보세요.
class Example { // 일단은 여러가지 type을 사용하지 않도록 분리해서 작업하는것이 제일 좋습니다. // 분리가 끝나면 적절한 type을 명시할 수 있는 Generic collection을 사용하구요. // 좋지 못한 경우 static public void BadCase() { // type에 대한 명시가 없는 어레이 리스트를 사용합니다. ArrayList list = new ArrayList(); // 값은 int형인데 int evenSum = 0; int oddSum = 0; for (int i = 0; i < 1000000; i++) { list.Add(i); } // item을 object로 받아서 처리하게 되네요 // 박싱이 일어납니다. foreach (object item in list) { if (item is int) { int num = (int)item; if(num % 2 ==0) { evenSum += num; } else { oddSum += num; } } } Console.WriteLine("EvenSum={0}, OddSum={1}", evenSum, oddSum); } // 적절하게 잘 사용한 경우 static public void GoodCase() { // type을 명시해줬습니다. List<int> list = new List<int>(); // int형을 사용했구요 int evenSum = 0; int oddSum = 0; for (int i = 0; i < 1000000; i++) { list.Add(i); } // num을 int형으로 받아서 처리합니다. // 박싱이 일어나지 않습니다. foreach (int num in list) { if (num % 2 == 0) { evenSum += num; } else { oddSum += num; } } Console.WriteLine("EvenSum={0}, OddSum={1}", evenSum, oddSum); } }
댓글 없음:
댓글 쓰기