- 개요
Addressables의 주요 기능은 에셋에 주소를 할당하고 사용하여 런타임에 로드하는 것이다
위와 같은 기능을 사용하여 모든 애셋을 한번에 로드하는 것이 아닌
필요한 시점에만 로드하여 초기 로딩 시간과 RAM 점유율을 대폭 감소시킬 수 있다
1) 문제 상황의 재연

위와 같이 코드를 구성하여 T 키를 누르면 prefab을 기반으로 GameObject를 생성한다
이후 프로젝트를 빌드한다 이때, 프리팹 애셋은 에디터에서 할당하여 스크립트에서 참조하므로 빌드에 포함된다

오브젝트가 생성된 후에 위와 같이 RAM 점유율이 급격하게 증가한 것을 확인할 수 있다
위와 같은 문제는 애셋에 대한 강한 참조로 인해 발생하는데,
로드된 씬의 스크립트가 참조하는 모든 프리팹과 그 프리팹과 연관된 모든 파일이 한꺼번에 RAM에 로드되어 발생한다
2) Addressable의 사용 - 강한 참조 문제의 해결

Addressables 애셋을 사용하기 위해서는 Addressables 패키지를 설치해야 한다

패키지 설치 이후에 상단 Window - Asset Management - Addressables - Groups 탭을 눌러
Addressables에 관련된 세팅을 진행할 수 있다

그룹을 생성하면 필수적인 파일들을 설치한 후에 기본 Addressable 그룹을 제공한다
애셋을 해당 그룹에 드래그 앤 드롭하여 그룹에 포함시킬 수 있다

또는 애셋을 선택하고 상단의 Addressable 속성을 체크하여 그룹에 포함시킬 수 있디

폴더를 Addressable 그룹에 포함시키는 것도 가능하다
폴더가 그룹에 들어가게 되면 폴더에 저장된 애셋들도 Addressable 그룹에 포함된다
3) 스크립트를 통한 Addressable 사용
3 - 1) 경로 문자열의 이용
public class Test : MonoBehaviour
{
private void Update()
{
if (Input.GetKeyDown(KeyCode.T))
{
AsyncOperationHandle<GameObject> operationHandle = Addressables.LoadAssetAsync<GameObject>("Assets/GameObject.prefab");
operationHandle.Completed += AsyncOperationHandle_Completed;
}
}
private void AsyncOperationHandle_Completed(AsyncOperationHandle<GameObject> asyncOperationHandle)
{
if (asyncOperationHandle.Status == AsyncOperationStatus.Succeeded)
{
Instantiate(asyncOperationHandle.Result);
}
else
{
Debug.Log("Failed to Load");
}
}
}
위와 같이 애셋이 저장된 경로의 문자열을 이용하여 Addressable 애셋을 로드하였다
이때 LoadAssetAsync 함수를 사용하여 비동기적으로 애셋을 로드하였고
애셋의 로드가 완료된 후에 콜백함수를 호출한다
콜백함수에서는 로드 결과에 따라 GameObject를 생성하거나 디버그 메세지를 출력한다
3 - 2) 3 - 1)의 코드의 람다화
public class Test : MonoBehaviour
{
private void Update()
{
if (Input.GetKeyDown(KeyCode.T))
{
Addressables.LoadAssetAsync<GameObject>("Assets/GameObject.prefab").Completed +=
(operationHandle) =>
{
if (operationHandle.Status == AsyncOperationStatus.Succeeded)
{
Instantiate(operationHandle.Result);
}
else
{
Debug.Log("Failed to Load");
}
};
}
}
}
3 - 1)에서 작성한 코드에서 함수를 람다로 생성하여 불필요한 함수 정의를 생략할 수 있다
3 - 3) 특정 타입 애셋의 참조
public class Test : MonoBehaviour
{
[SerializeField]
private AssetReference assetReference;
private void Update()
{
if (Input.GetKeyDown(KeyCode.T))
{
assetReference.LoadAssetAsync<GameObject>().Completed +=
(operationHandle) =>
{
if (operationHandle.Status == AsyncOperationStatus.Succeeded)
{
Instantiate(operationHandle.Result);
}
else
{
Debug.Log("Failed to Load");
}
};
}
}
}
AssetReference 클래스를 사용하면 로드한 애셋을 특정 타입으로 사용할 수 있다
위와 같이 에디터에서 assetReference 변수의 값을 할당받고
LoadAssetAsync 함수의 제네릭 인자를 GameObject로 넘겨주어 로드한 애셋을 GameObject로 사용한다
3 - 4) 라벨의 사용

라벨을 사용하면 여러 애셋에 동일한 라벨을 붙여 한 번에 묶음으로 로드할 수 있다
public class Test : MonoBehaviour
{
[SerializeField]
private AssetLabelReference assetLabelReference;
private void Update()
{
if (Input.GetKeyDown(KeyCode.T))
{
Addressables.LoadAssetsAsync<GameObject>(assetLabelReference, (gameObject) => {
if (gameObject)
{
Instantiate(gameObject);
}
else
{
Debug.Log("Failed to create " + gameObject.name);
}
});
}
}
}
AssetLabelReference 클래스를 사용하여 생성한 라벨이 붙여진 애셋들을 한번에 로드할 수 있다
LoadAssetsAsync 함수에 인자로 에디터에서 설정한 AssetLabelReference를 넘겨주어 사용한다
라벨이 붙여진 애셋을 문제없이 로드했다면 생성하고, 아니라면 애셋의 이름을 출력한다
3 - 5) 커스텀 타입의 참조
[System.Serializable]
public class AssetReferenceCharacter : AssetReferenceT<GameObject> {
public AssetReferenceCharacter(string guid) : base(guid) { }
}
public class Test : MonoBehaviour
{
[SerializeField]
private AssetLabelReference assetLabelReference;
[SerializeField]
private AssetReferenceCharacter characterAssetReference;
...
}
AssetReferenceT<타입> 클래스를 상속받아 로드한 애셋을 원하는 커스텀 타입으로 사용할 수 있다
위의 예시에서는 characterAssetReference 변수가 GameObject 타입 애셋만 할당가능하도록 코드를 구성하였다
3 - 6) 로드와 생성의 동시 처리
public class Test : MonoBehaviour
{
[SerializeField]
private AssetReferenceGameObject assetReferenceGameObject;
private void Update()
{
if (Input.GetKeyDown(KeyCode.T))
{
assetReferenceGameObject.InstantiateAsync();
}
}
}
InstantiateAsync 함수를 사용하면 애셋을 로드함과 동시에 생성할 수 있다
예시에서는 assetReferenceGameObject 변수로부터 함수를 호출하여 GameObject 애셋을 로드하고 생성한다
3 - 7) 로드된 인스턴스의 해제
public class Test : MonoBehaviour
{
[SerializeField]
private AssetReferenceGameObject assetReferenceGameObject;
private GameObject spawnedGameObject;
private void Update()
{
if (Input.GetKeyDown(KeyCode.T))
{
assetReferenceGameObject.InstantiateAsync().Completed += (asyncOperation) => spawnedGameObject = asyncOperation.Result;
}
if (Input.GetKeyDown(KeyCode.U))
{
assetReferenceGameObject.ReleaseInstance(spawnedGameObject);
}
}
}
Addressable 애셋을 로드하면 내부적으로 참조 카운트가 증가하는데, 이 카운트가 0이 되어야 메모리에서 제거된다
따라서 애셋을 로드한 후에 해제하지 않는다면 메모리 누수가 발생하게 된다
ReleaseInstance 함수를 호출하여 로드된 애셋을 해제할 수 있다
따라서 반드시 로드 - 해제의 과정은 짝을 이뤄 수행해야 한다
4) Addressable 기능

Addressable에서 추가적으로 사용할 수 있는 기능은 다음과 같다
- Profiles 탭 : 개발 환경에 따라 애셋의 로드 경로를 다르게 설정할 수 있음
- Tools - System 탭 : Addressable에 관련된 설정을 조정가능
- 최종 실행 결과

최종적으로 Addressable 애셋을 사용하는 경우 위와 같이 RAM 사용량을 감소시킬 수 있다
'유니티 엔진 > 유니티 엔진의 구성' 카테고리의 다른 글
| 유니티 엔진의 구성 - 43) 유니티 CCD (0) | 2026.05.18 |
|---|---|
| 유니티 엔진의 구성 - 42) Addressables를 사용한 원격 배포 (0) | 2026.05.13 |
| 유니티 엔진의 구성 - 40) JSON과 JsonUtility (0) | 2026.05.04 |
| 유니티 엔진의 구성 - 39) NullReferenceException 예외 해결 (0) | 2026.04.28 |
| 유니티 엔진의 구성 - 38) 래그돌(Ragdoll) (0) | 2026.04.27 |