본문 바로가기

C# 일기

1. 값 형식 변수와 참조 형식 변수

우리가 C++에서 다루었던 변수들은 다양했다.

 

3. 변수(Variable)에서 설명했던 변수는 저장하고 싶은 데이터의 자료형과 이름을 정하고, 그 값을 대입하면 됐었다.

 

이렇게 선언된 변수는 메모리영역 중 스택에 값이 저장되고, 그 값의 이름을 호출하면 그 값이 대입되는 방식이다.

 

예를들어, int a = 10; 이라고 변수를 선언했다면, 이 변수를 선언한 함수에서는 a는 곧 10이다.

 

스택영역의 특성상, 선언된 변수는 선언이 되었던 함수가 종료되면 방을 빼게 되어있다.

 

즉, 변수의 이름도, 값도 전부 사라지는 것이다.

 

이러한 변수를 값 형식의 변수라고 부른다.

 

스택 영역에 특정 값이 저장되고, 그 값을 변수의 이름을 통해 사용할 수 있는 것이다.

 

직접 값을 갖는 값 형식 변수 말고, 주소값을 갖는 참조 형식 변수가 있다.

 

C#에서, object라는 자료형을 통해 선언한 변수가 참조 형식 변수중 하나인데, 이번엔 이를 통해 다루어 보겠다.

using System;

namespace Favor
{
   internal class Program
   {
      static void Main(string[] args)
      {
         int a = 10;
         object b = 3.14;
      }
   }
}

 

여기서 a는 자료형을 int로 선언하고, 10이라는 값을 스택 영역에 int만큼 할당한다. 그리고 이것을 a라고 불렀다.

 

이와 달리 object b는 자료형을 명시하지 않아도 3.14라는 값이 대입이 된다.

 

object 자료형은 컴파일러가 알아서 대입된 값에 맞게 자료형의 크기를 판단하여 메모리 공간을 할당해준다.

 

하지만 object는 값 형식 변수가 아닌 참조 형식 변수이다.

 

참조 형식 변수와 값 형식 변수는 무엇이 다를까?

 

 

 

참조 형식 변수는 값 형식 변수와 다르게, 스택 영역만을 사용하는 것이 아닌, 힙 영역도 사용한다.

 

이 두 영역에는 각각 다른 값들이 할당이 되는데,

 

우선 값 형식 변수나 참조 형식 변수나, 저장해야 할 자료의 값이 저장되는 공간이 있어야하기 마련인데,

 

값 형식 변수 때는 스택영역에 저장되었지만 참조 형식 변수는 힙 영역에 저장된다.

 

 

 

그러면 스택 영역에는 무엇이 저장되는가 하면, 여기에는 힙 영역에 저장된 자료의 값이 저장된다.

 

우리가 포인터에 대해 알아보았을 때와 유사하다고 생각하면 된다.

 

포인터 변수는 특정 변수의 주소값을 대입하면, 그 주소값이 저장되고, 이를 역참조를 통해 값에 접근할 수 있었다.

 

참조 형식 변수도 마찬가지로, 특정 데이터의 주소값을 저장하며, 그 데이터에 접근할 수 있다.

 

변수의 선언은 한 번 이루어졌지만, 3.14와 b가 동시에 할당된 것이다.

 

이렇게 참조 형식 변수를 선언하면, 위에서 말한 포인터 변수와 유사하게 작동하여

 

b를통해 3.14에 접근하고, 초기화 할 수 있다.

 

 

using System;

namespace Favor
{
   internal class Program
   {
      static void Main(string[] args)
      {
         int a = 10;
         object b = 3.14;
      } // 이 시점에서 a와 a에 대입된 10 할당 해제, 3.14의 주소값이 저장된 b만 할당 해제
   }// 이 시점이 지나도 b의 값인 3.14가 메모리에서 할당 해제되지 않음
}// 값은 있으나 호출할 수 없는 값 3.14를 GC가 수거해 할당해제

 

그렇다면 헷갈리지도 않고, 자료형을 잘못 선언할 일도 없게 모든 변수를 object형으로 선언하면 안되는걸까?

 

문제는 C#의 가비지 컬렉터에 있다.

 

GarbageCollector(GC)는 C#에 있는 기능 중 하나로, 쓰레기 값을 스스로 수거하여 할당 해제시키는 기능을 수행한다.

 

위에서 값 형식의 변수는 스택에, 참조 형식 변수는 힙과 스택 영역에 할당된다고 했었다.

 

스택 영역의 데이터는 전술했듯 선언했던 함수의 } (맺는 중괄호)를 만나면 할당이 해제된다.

 

그러나 힙 영역은 그렇지 않다.

 

참조 형식 변수는 스택 영역에 값을 가리키는 변수를, 힙 영역에 변수에 해당하는 값을 저장한다고 했었다.

 

그러면 함수가 종료되고 주소값이 저장돼있는 변수는 할당이 해제되나. 그 주소값에 있는 값은 해제되지 않는다.

 

이러한 현상을 막기 위해 GC가 호출되어 힙 영역의 값을 할당 해제시킨다.

 

따라서 구조상, object형 변수의 선언이 남용될 시, GC가 반복적으로 호출되어 성능면에서 불리하게 작용되므로

 

최대한 저장할 자료에 알맞은 자료형을 선언하여 변수를 선언하는 것이 좋다.

 

물론, object형 변수를 선언하면, 변수가  어떠한 값을 갖고있는지, 어떠한 값을 저장할 수 있는지 명확히 알기 어렵기 때문에 가독성 측면에서도 남용해선 좋지 않다.

 

 

 

 

 

 

 

'C# 일기' 카테고리의 다른 글

5. 얕은 복사(Shadow Copy)와 깊은 복사(Deep Copy)  (0) 2024.03.05
4. 생성자 (Constructor)  (0) 2024.03.04
3. foreach문  (0) 2024.03.04
2. 배열  (0) 2024.03.04
0. C# 입출력 (Console.)  (0) 2024.03.04