Unity Life Cycle (생명주기)
생명주기 하면 가장 먼저 떠오른 키워드는 렉시컬 스코프 였다.
유니티서 생명주기는 MonoBehaviour 기반 스크립트를 관리하는 순서이자 흐름이다.
모든 Unity 컴포넌트는 생성 → 초기화 → 실행 → 종료 단계를 거치며
각 시점마다 특정 콜백 함수들이 호출된다.
전반적인 실행 순서는 다음과 같다
- Awake()
- OnEnable()
- Start()
- Update()
- FixedUpdate()
- LateUpdate()
- OnDisable()
- OnDestroy()
생명주기 관련 함수들에 대해서 각각 조금 더 알아보자
Awake()
가장 먼저 호출되는 초기화 함수로 게임 오브젝트 활성화 여부와 상관없이 스크립트가 메모리에 로드될 때 한 번 호출된다.
주로 참조 연결, 싱글톤 인스턴스 지정 등에 사용된다.
Start와 헷갈리지 않게 주의하자.
차이점을 묻는 질문이 자주 나온다고 한다.
Awake는 오브젝트가 생성될 때 호출, Start는 활성화 된 후 첫 프레임에 호출된다.
void Awake()
{
Debug.Log("Awake 호출됨");
player = GameObject.Find("Player");
}
OnEnable()
오브젝트가 활성화 될 때마다 호출된다.
비활성화 후 다시 재활성화 하면 그 때도 호출된다.
이벤트 구독 등록에 자주 사용된다.
void OnEnable()
{
EventManager.OnHit += OnHitHandler;
}
Start()
오브젝트가 활성화 된 직후, 첫프레임에 한 번만 호출된다.
Awake 이후에 호출되므로, 헷갈리지 말자.
Start에서도 초기화를 하기 때문에 Awake랑 차이를 잘 인지해야 한다.
의존성 없는 내부 초기화는 주로 Awake에서, 다른 오브젝트나 데이터 의존성 초기화는 Start가 적절하다.
오브젝트 활성화가 보장되어야 터지지 않기 때문이다.
void Start()
{
Debug.Log("Start 호출됨");
// 의존성 초기화
}
Update()
매 프레임마다 호출되는 대표적인 실행 루프다.
프레임 속도(FPS)에 따라 호출 주기가 달라진다.
입력 처리, 애니메이션, 간단한 이동 등에 사용된다.
void Update()
{
transform.Translate(Vector3.forward * Time.deltaTime);
}
위 코드에서 Time.deltaTime을 곱해주는 부분이 있는데 이것은 업데이트가 프레임 단위로 실행되는 것에 의해, 환경에 따라 의도치않게 코드가 다르게 동작하는 것을 막기 위함이다.
예를들어, 200FPS가 출력되는 환경에서는 Vector3를 200번 옮길 거고, 60FPS 출력되는 환경에서는 60번 옮길 거다.
이거는 개발자의 의도와 맞지 않다.
여기서 Time.deltaTime을 곱해주는 것으로, 프레임 수와 관계없이 시간에 의존해 올바른 횟수로 업데이트 처리를 할 수 있게 되는 것이다.
FixedUpdate()
고정된 간격(기본 0.02초 = 50fps)으로 호출된다.
물리 연산(Physics, Rigidbody) 관련 코드에 주로 사용된다.
실제 프레임 수와 관계없이 일정한 주기로 실행된다.
void FixedUpdate()
{
rb.AddForce(Vector3.forward);
}
여기서 Update()도 이동로직, FixedUpdate()도 이동로직을 적용할 수 있는데 그 기준은 물리 연산에 있다.
단순 좌표 계산의 경우는 Update에, 가속 감속 충돌 등과 관련된 물리 연산은 주로 FixedUpdate에서 관리한다.
LateUpdate()
모든 Update()가 끝난 후 한 번 더 호출되는 루프다.
주로 카메라 추적이나 후처리 로직에 사용된다.
void LateUpdate()
{
camera.transform.position = player.transform.position + offset;
}
OnDisable()
오브젝트가 비활성화될 때 호출된다.
이벤트 해제, 코루틴 중단, 구독 해제 등에 활용된다.
void OnDisable()
{
EventManager.OnHit -= OnHitHandler;
}
OnDestroy()
오브젝트가 씬에서 제거되거나 게임 종료 시 호출된다.
리소스 정리, 파일 저장, 로그 기록 등에 사용된다.
void OnDestroy()
{
Debug.Log("객체가 파괴됨");
// 파괴 되는 순간에 실행할 로직
}
도식화 하면 아래와 같다
[객체 생성]
↓
Awake()
↓
OnEnable()
↓
Start()
↓
Update() ─ FixedUpdate() ─ LateUpdate()
↓
OnDisable()
↓
OnDestroy()
그런데 여기서 실제로는 어떻게 동작하는지 찍어보았는데...
using System.Reflection;
using UnityEngine;
public class ExampleScript : MonoBehaviour
{
void Awake()
{
Debug.Log($"{MethodBase.GetCurrentMethod().Name} 호출");
}
void OnEnable()
{
Debug.Log($"{MethodBase.GetCurrentMethod().Name} 호출");
}
void Start()
{
Debug.Log($"{MethodBase.GetCurrentMethod().Name} 호출");
}
void Update()
{
Debug.Log($"{MethodBase.GetCurrentMethod().Name} 호출");
}
void FixedUpdate()
{
Debug.Log($"{MethodBase.GetCurrentMethod().Name} 호출");
}
void LateUpdate()
{
Debug.Log($"{MethodBase.GetCurrentMethod().Name} 호출");
}
void OnDisable()
{
Debug.Log($"{MethodBase.GetCurrentMethod().Name} 호출");
}
void OnDestroy()
{
Debug.Log($"{MethodBase.GetCurrentMethod().Name} 호출");
}
}
(리플렉션은 실제 런타임 중에는 무거워서 사용하지 않는게 좋지만 간단한 디버깅 코드니까 재미로 써봤다.)
실제 콘솔에는 아래와 같이 찍혔다


???
분명 위에서 Update 다음 FixedUpdate라고 적어놨는데 왜 이런 현상이??
이건 FixedUpdate가 Update 보다 항상 먼저 실행되는 건 아니고, 프레임 단위로 봤을 때 먼저 실행될 수 있는 상황이 있는 것이다.
고정 시간(0.02초) 마다 FixedUpdate()를 실행하기 때문이다.
즉 최초의 Update()가 0.02초보다 빠르게 실행되면 Update()가 먼저 실행되는 것처럼 보일 것이다.
또한, 일정 프레임이 넘어가면 FixedUpdate 사이에 Update가 여러번 호출 될 수도 있다.
그 외에도 여러 생명주기 이벤트가 있지만 주로 위에 소개한 함수 위주로 사용된다.
| Reset() | 인스펙터에서 Reset 버튼 클릭시 호출 |
| OnApplicationPause() | 앱이 일시정지될 때 (모바일) |
| OnApplicationQuit() | 앱 종료 시 한 번 호출 |
| OnValidate() | 에디터에서 값 변경 시 즉시 호출 |
생명주기를 올바르게 이해하는 것은 유니티 최적화에 다가가는 첫 걸음이니 숙지하고 넘어가자.
'Unity' 카테고리의 다른 글
| Unity - EventSystem (이벤트 시스템) (0) | 2025.10.20 |
|---|---|
| Unity - Coroutine, yield, Invoke, IEnumerator (0) | 2025.10.17 |
| Unity - Rigidbody, Collider - 물리, 충돌 처리 (0) | 2025.10.16 |
| Unity - Transform, 위치 이동 (0) | 2025.10.15 |
| Unity - 오브젝트(Object), 컴포넌트(Component), 오브젝트 풀링(Object Pooling) (0) | 2025.10.14 |