| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 | 31 |
- 원신
- 취미
- 게임용어
- 스파르타내일배움캠프TIL
- 컴포넌트
- spritelibrary
- c#
- 붕괴스타레일
- spritemask2d
- 게임분석
- 블렌더
- 점프
- 내일배움캠프
- 공부
- 유니티
- 연습
- 스파르타내일배움캠프
- ag 내일배움캠프
- 코딩
- 붕괴 스타레일
- LookAt
- 뭐드라
- 까먹기전에메모
- 게임 회사
- 나만의 견해
- 후기
- 프로그래밍
- 취업
- til
- materialpropertyblock
- Today
- Total
덴바의 노트
유니티 C#, C++ 그리고 Null 본문

오늘의 키워드
- 유니티와 C++의 관계
- Null 처리의 중요성
얀녕하세요, 오늘은 회사를 다니면서 새로 배운 내용들을 잊기 전에 메모해둘 필요가 있다고 느껴서 포스팅 해봅니다.
유니티와 C++의 관계
기본적으로 유니티는 C#을 사용하기 때문에 당연하게 C++과는 관계 없을 거라고 생각할 수 있습니다.
하지만 실제 Unity 엔진의 코어(렌더링, 물리, 오디오, 메모리 관리 등)은 C++로 구현되어 있습니다.
그럼 왜 우리는 C++로 이루어진 엔진을 C#으로 코딩을 할까? 라는 의문이 있습니다.
이유는 C#이 생산성, 유지보수, 개발 속도가 매우 높은 반면,
C++은 메모리 버그가 많고, 개발 속도가 느리며, 가독성 생산성이 낮다고 판단되기 때문입니다.
특히, C++은 컴파일과 링크 시간이 길기 때문에 게임 엔진 개발로서는 부적합하다고 판단했다 생각합니다.
Null 처리의 중요성
댕글링 포인터(Dangling Pointer)란?
정의:
이미 해제되거나 유효하지 않은 메모리를 가리키고 있는 포인터
이 현상은 유니티에서 실제로 쉽게 볼 수 있는 현상입니다.
예시를 들자면, GameObject 입니다.
아까 위에서 언급했듯이, 유니티 엔진의 코어 기능들은 C++로 구현되어 있습니다.GameObject obj = new GameObject();

즉, 실제로 GameObject를 생성하게 되면 코어의 C++ 코드가 실행됩니다.
여기서 핵심은 엔진의 C++ 코드가 생성되면서 C++객체가 생성됩니다.
동시에 이를 접근하고 관리하기 위해서 C#의 객체를 생성하고 C++의 객체를 참조합니다.
Destroy(obj);
Destroy 메소드 또한 코어 함수 중 하나입니다.
Destroy가 호출되면, C++의 객체가 파괴됩니다.
이 순간 댕글링 포인터 현상이 발생합니다.
C++의 객체는 파괴되지만, 이를 참조하기 위해 생성된 C# 객체는
아직도 C++ 객체의 주소를 참조하고 있는 문제가 발생합니다.
이렇게 되면 해당 C# 객체는 GC에 빠르게 수거 대상이 되지 않습니다.
즉, 불필요한 데이터가 계속해서 메모리에 쌓이게 되는 것입니다.
그럼 이를 유니티에서 어떻게 하면 확인할 수 있을까요?
private void Update()
{
if(Input.GetKeyDown(KeyCode.F1))
{
Destroy(obj);
}
if (Input.GetKeyDown(KeyCode.F2))
{
Debug.Log(obj);
Debug.Log(obj.GetType());
Debug.Log(obj == null);
}
}
위와 같은 방식으로 테스트하면 어떤 결과가 나올까요?

obj가 null처리 되었음에도 불구하고 obj의 타입은 아직 UnityEngine.GameObject임을 알려줍니다.
이는 아직 C# 객체가 제대로 파괴되지 않았기 때문입니다.
그럼 이를 방지하기 위해서는 어떻게 해야할까요?
간단합니다.
파괴한 객체를 Null 처리해주는 것입니다.
private void Update()
{
if(Input.GetKeyDown(KeyCode.F1))
{
Destroy(obj);
obj = null;
}
if (Input.GetKeyDown(KeyCode.F2))
{
Debug.Log(obj);
Debug.Log(obj.GetType());
Debug.Log(obj == null);
}
}
이렇게 하면 어떤 결과가 나올까요?

객체가 null처리가 확실히 되면서 해당 객체와의 레퍼 연결이 끊깁니다.
즉, 이는 GC의 대상이 되면서 빠르게 메모리 관리가 될 수 있습니다.
C++에서는 소멸자 등을 사용해서 데이터를 관리해주지만, C#은 GC가 메모리를 관리해준다는 점.
자동으로 메모리가 관리되지만, 그럼에도 불구하고 레퍼런스 타입의 객체는 항상 null처리를 해주는 것이 중요합니다.
최근 저는 IDisposable을 구현하는 클래스에 상속해서 Dispose 패턴을 꾸준히 구현합니다.
작은 프로젝트의 경우에는 굳이 할 필요는 없을 수 있지만, 프로젝트가 커질 수록 메모리 관리는 중요해집니다.
이상으로 포스팅을 마치도록 하겠습니다.
감사합니다.

'프로그래밍 노트' 카테고리의 다른 글
| 유니티 상호작용 가능한 대상을 바라보는 LookAt (0) | 2025.04.21 |
|---|---|
| 유니티 Rigidbody의 AddForce와 등가속도 원리를 이용한 [점프 구현] (0) | 2025.03.08 |