박싱이란 것은 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);
}
}
댓글 없음:
댓글 쓰기