변수를 선언할 때 명시하는 데이터 형식에 따라 변수에 넣을 수 있는 데이터 종류가 달라집니다. 변수를 선언하면 C#은 데이터를 저장할 수 있는 공간을 메모리에 예약해 둡니다. 그 메모리 공간은 데이터 형식마다 할당되는 구조가 다릅니다. 그리고 데이터 형식마다 할당되는 메모리 공간 크기도 다릅니다. 그 메모리 공간 때문에 생기는 문제들이 있는데 C# 스크립트를 작성하면서 데이터를 입력 출력할 때 굉장히 중요합니다.
이번 게시글에서는 메모리 공간에 어떤 차이점이 있는지 알아봅시다.
데이터 형식마다 메모리 공간 크기가 다르다

메모리는 데이터를 저장하는 역할을 합니다. 데이터를 저장한다는 목적만 놓고 보면 SSD나 HDD와 비슷한 일을 할 것 같지만 다릅니다. SSD나 HDD 같은 스토리지 드라이브는 컴퓨터가 종료돼도 데이터를 보관하지만 메모리는 단기 데이터 스토리지입니다. 컴퓨터가 실시간으로 사용하는 정보를 저장하고 사용하지 않는다면 파기시키죠. 가령 프로그램이 사용하는 변수 같은 것이요.
예시로 C# 기본 데이터 형식 int와 long을 명시하여 선언한 변수 두 개가 있습니다. 하는 역할은 둘 다 정수를 저장하는 정수 데이터 형식입니다. 쉽게 말해서 숫자를 저장하는 데이터 형식입니다. 메모리 공간 크기도 같은지 확인해 봅시다. 직관적으로 확인하기 위해 큐브 오브젝트 스케일을 데이터 형식 크기로 바꿔봅시다.

DataType Scene을 생성하여 새로운 Scene을 불러옵니다. 그리고 위 사진처럼 Scene을 구성합시다. Button 2개를 만들고 3D 오브젝트 큐브를 생성했습니다. Button의 Text는 int와 long으로 수정합니다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DataTypeScale: MonoBehaviour
{
public Transform cubeTransform;
void Start()
{
cubeTransform = GameObject.Find("Cube").GetComponent<Transform>();
}
public void IntSize()
{
cubeTransform.localScale = new Vector3(sizeof(int), sizeof(int), sizeof(int));
}
public void LongSize()
{
cubeTransform.localScale = new Vector3(sizeof(long), sizeof(long), sizeof(long));
}
}
DataTypeScale.cs 스크립트를 생성합니다. Start 메서드에서 호출된 GameObject.Find(“Cube”)는 Scene에서 게임 오브젝트 이름이 Cube인 오브젝트를 찾아주는 기능입니다. 큐브 오브젝트 Transform 컴포넌트의 Scale 프로퍼티를 수정하는 게 목표이므로 Transform 컴포넌트를 변수에 대입합니다. 그리고 메서드를 생성합니다. 각 메서드는 int, long 데이터 형식 크기를 큐브 오브젝트 스케일로 변경하는 기능을 합니다.

각 버튼에 스크립트를 연결하고 각 버튼 onClick 이벤트 함수에 메서드를 등록합니다.
플레이 버튼을 누르고 각 버튼을 클릭해보면 큐브 스케일이 바뀌는 것을 볼 수 있습니다. 좀 극적으로 크기 차이가 있긴 하지만 어쨌든 비슷한 역할을 하는 데이터 형식이라도 크기 차이가 있다는 것을 알 수 있습니다.
물론 메모리 공간이 크면 더 많은 데이터를 담을 수 있답니다. int는 -2,147,483,648 ~ 2,147,483,647까지 담을 수 있는 반면에 long은 -922,337,203,685,477,508 ~ 922,337,203,685,477,507까지 담을 수 있습니다. 훨씬 크죠? 같은 정수형이라도 프로그램 사용처가 다르기 때문에(ex. 게임, 재무관리 프로그램, 엘리베이터) 다양한 정수 데이터 형식이 있습니다. 정수 데이터 타입은 8개가 있는데 어떤 방식으로 세분화되었는지에 관해서는 게임 개발에 꼭 필요한 내용이 아니기 때문에 생략하겠습니다.
데이터 형식에 따라 할당되는 메모리 공간이 다르다는 건 알았습니다. 이제 간단하게 데이터 형식의 종류를 훑어봅시다.
C# 기본 데이터 형식
저희가 다운로드한 유니티는 .NET Standard 2.0을 지원합니다. .NET은 여러 플랫폼에서 호환되는 프로그램을 개발하기 위한 무료 오픈 소스 개발 플랫폼입니다. 최대한 간단하게 생각하면 윈도우10을 목표로 개발한 프로그램이 안드로이드에서도 실행된다고 생각하면 됩니다.
C# 기본 데이터 형식 .NET Standard 2.0
C# 기본 데이터 형식 .NET Standard 2.0 | |||||||
특징 | 데이터 형식 | 크기(byte) | 데이터 범위 | 변수 선언 | |||
값 | 숫자 | 정수 | byte | 1 | 0 ~ 255 | byte variable = 123; | |
sbyte | 1 | -128 ~ 127 | sbyte variable = 123; | ||||
short | 2 | -32,768 ~ 32,767 | short variable = 123; | ||||
ushort | 2 | 0 ~ 65,535 | ushort variable = 123; | ||||
int | 4 | -2,147,483,648 ~ 2,147,483,647 | int variable = 123; | ||||
uint | 4 | 0 ~ 4,294,967,295 | uint variable = 123; | ||||
long | 8 | -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 | long variable = 123; | ||||
ulong | 8 | 0 ~ 18,446,744,073,709,551,615 | ulong variable = 123; | ||||
부동 소수점 | 단일 정밀도 | float | 4 | (유효 자릿수 : 7자리) -3.40282347 E + 38 ~ 3.40282347 E + 38 | float variable = 1.23f; | ||
복수 정밀도 | double | 8 | (유효 자릿수 : 15자리) -1.7976931348623157 E + 308 ~ 1.7976931348623157 E + 308 | double variable = 1.23; | |||
고정 소수점 | decimal | 16 | (유효 자릿수 : 28자리) -79,228,162,514,264,337,593,543,950,335 ~ 79,228,162,514,264,337,593,543,950,335 | decimal variable = 1.23m; | |||
문자 | char | 2 | 문자 한 개(유니코드) | char variable = ‘굳’; | |||
논리 | bool | 1 | true, false | bool variable = true; | |||
참조 | 문자열 | string | 정해진 크기나 담을 수 있는 데이터의 범위가 정해져 있지 않음 | string variable = “안녕하세요.”; | |||
오브젝트 | object | 컴파일러가 인지하는 데이터 형식에 따라 달라짐 | object variable = “특이하네요.”; |
.NET Standard 2.0이 지원하는 기본 데이터 형식은 위 표와 같습니다. 위 데이터 형식들만 봐도 많은데 외울필요 없습니다. 게임에서 가장 많이 쓰이는 유형은 int, string, bool, float입니다. 다른 데이터 타입이 필요하다면 찾아보면 돼요. 예를 들어 게임 주인공의 레벨이 250이 최대라면 굳이 int 형을 사용할 필요가 없습니다. 255까지 저장 가능한 byte를 명시하는 게 int보다 크기도 작으니 훨씬 좋죠.
숫자 데이터 형식마다 데이터가 저장되는 구조를 알면 굉장히 특이한 로직으로 프로그램을 개발하기도 합니다. 멋진 일이지만 유니티를 사용한 게임 개발에는 데이터 형식마다 어떤 구조로 데이터가 저장되는지 외울 필요 없습니다. 물론 저장되는 구조를 알아도 활용하기는 쉽지 않고요. 하지만 꼭 알아야 할 게 있다면 값 형식과 참조 형식의 차이점입니다. 둘의 가장 큰 차이점은 데이터가 저장되는 메모리 공간이 다른 것인데 그거부터 알아봅시다.
메모리 영역 스택과 힙
스택

스택은 값 형식 데이터 형식의 데이터가 저장되는 메모리 영역입니다. 스택은 메모리 공간이 위쪽에만 생기고 없어질 때는 가장 최근에 생긴 위쪽 메모리 공간부터 없어집니다. 만약 제일 아래에 있는 데이터를 제거하려면 위에 쌓여 있는 데이터를 제거해야 합니다. 스택에 할당되는 변수의 크기는 데이터 형식에 따라 일정합니다. 변수의 생명 주기가 다 하면 자동으로 데이터를 제거합니다. 예를 들어, 메서드 지역에 선언된 지역 변수는 메서드가 묶고 있는 중괄호가 끝나면 자동으로 제거됩니다.
힙

힙은 참조 형식의 데이터 형식이 저장되는 메모리 영역입니다. 스택처럼 메모리 공간이 생기거나 없어지는 순서가 따로 없습니다. 힙에 메모리 공간이 생기는 위치는 모호합니다. 힙에 할당되는 데이터의 크기가 일정하지 않기 때문입니다. 참조 형식의 데이터 형식은 힙과 스택을 함께 사용하는데, 힙 영역에는 데이터를 저장하고 스택 영역에는 데이터가 저장되어 있는 힙 메모리 공간의 주소를 저장합니다. 데이터를 직접 저장하는 대신 실제 데이터가 저장되어 있는 메모리의 주소를 “참조”한다고 해서 “참조 형식”이라고 합니다. 할당된 메모리 공간이 없어지는 순간은 더 이상 데이터를 참조하는 곳이 없을 때 가비지 콜렉터가 데이터를 수거해갑니다.
가비지 콜렉터는 C#으로 만든 프로그램을 실행시키는 CLR의 기능인데 유니티를 사용한 게임 개발에는 굳이 알 필요 없습니다. 그냥 힙 영역의 데이터를 수거해가는 기능이라고만 알아두면 됩니다.
다음 시간에는 무엇을 배우나요?
오늘 알려드린 데이터 형식에 관한 내용은 생략된 내용이 엄청 많아요. 꼭 필요한 내용만 알려드렸습니다. 유니티를 활용한 게임 개발에 꼭 필요한 내용은 아니지만 프로그래밍에 관심이 있는 분들은 알면 좋은 내용들이니 찾아보시는 걸 추천드립니다.
그런데 기본 데이터 형식 말고 복합 데이터 형식도 있답니다. 복합 데이터 형식도 알아봐야겠죠? 그중에서 대표로 클래스(class)에 대해 알아봅시다. 프로그래밍을 조금이라도 배우신 분들은 객체 지향 프로그래밍(OOP)를 들어보셨을 겁니다. 클래스를 설명할 때 빠지지 않고 나오는 것이 객체 지향 프로그래밍인데 유니티 게임 오브젝트와도 연관이 많답니다. 왜냐하면 게임 오브젝트는 컴포넌트로 구성돼 있고 컴포넌트는 클래스이거든요.
다음 시간에 만나요~ 제발~