Skip to content

Unity Addressable Assets

Addressable Assets System은 Resources 폴더와 AssetBundle의 단점을 해소하기 위해 도입된 Unity의 공식 에셋 관리 시스템입니다. 에셋에 주소(address) 문자열을 부여하고 비동기로 로드하며, 로컬·원격 배포를 동일한 API로 처리합니다.


비교 항목ResourcesAssetBundleAddressables
빌드 포함 여부항상 포함수동 관리그룹 설정으로 제어
원격 배포불가가능 (복잡)기본 지원
의존성 관리수동수동자동
메모리 해제Resources.UnloadAssetBundle.UnloadHandle.Release
주소 참조경로 문자열수동 매핑주소 / 라벨

  • Address — 에셋을 식별하는 임의의 문자열 키 ("Characters/Hero")
  • Label — 여러 에셋을 묶는 태그 ("preload", "ui")
  • Group — 빌드 전략(로컬/원격)을 공유하는 에셋 묶음
  • Profile — 로컬·원격 경로를 환경(개발/스테이징/프로덕션)별로 설정

using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
public class HeroLoader : MonoBehaviour
{
AsyncOperationHandle<GameObject> _handle;
async void Start()
{
// 주소로 로드
_handle = Addressables.LoadAssetAsync<GameObject>("Characters/Hero");
GameObject prefab = await _handle.Task;
if (_handle.Status == AsyncOperationStatus.Succeeded)
Instantiate(prefab);
}
void OnDestroy()
{
// 반드시 Release — 내부 참조 카운트를 감소시켜 메모리 해제
if (_handle.IsValid())
Addressables.Release(_handle);
}
}
async void LoadUIAssets()
{
var handle = Addressables.LoadAssetsAsync<Sprite>("ui", sprite =>
{
// 각 에셋이 로드될 때마다 콜백 호출
Debug.Log($"로드됨: {sprite.name}");
});
await handle.Task;
if (handle.Status == AsyncOperationStatus.Succeeded)
{
IList<Sprite> sprites = handle.Result;
// 사용 완료 후 해제
Addressables.Release(handle);
}
}
async void LoadGameScene()
{
var handle = Addressables.LoadSceneAsync("Scenes/GameLevel",
UnityEngine.SceneManagement.LoadSceneMode.Additive);
await handle.Task;
// 씬 언로드 시
await Addressables.UnloadSceneAsync(handle).Task;
}

Addressables는 참조 카운팅 방식으로 메모리를 관리합니다. LoadAssetAsync 한 번 → Release 한 번으로 균형을 맞춰야 합니다.

// ❌ 잘못된 패턴 — Release 없이 재로드 반복 → 메모리 누수
for (int i = 0; i < 100; i++)
Addressables.LoadAssetAsync<Texture2D>("icon");
// ✅ 올바른 패턴 — 핸들 보관 후 사용 완료 시 Release
public class AssetManager : MonoBehaviour
{
readonly Dictionary<string, AsyncOperationHandle> _handles = new();
public async Task<T> LoadAsync<T>(string address)
{
if (_handles.TryGetValue(address, out var cached))
return (T)cached.Result;
var handle = Addressables.LoadAssetAsync<T>(address);
await handle.Task;
_handles[address] = handle;
return handle.Result;
}
public void Unload(string address)
{
if (_handles.TryGetValue(address, out var handle))
{
Addressables.Release(handle);
_handles.Remove(address);
}
}
void OnDestroy()
{
foreach (var handle in _handles.Values)
Addressables.Release(handle);
_handles.Clear();
}
}

그룹 용도빌드 설정예시
로컬 필수 에셋Local / Build Path기본 UI, 공통 셰이더
원격 레벨 에셋Remote / CDN Path스테이지별 씬, 캐릭터
DLCRemote / 별도 카탈로그추가 콘텐츠

  1. Profile 에서 Remote Build Path / Remote Load Path 설정
  2. Addressables > Build > New Build > Default Build Script 실행
  3. ServerData/ 폴더의 번들 파일을 CDN에 업로드
  4. 런타임에 Addressables.InitializeAsync() → 카탈로그 업데이트 체크
async void CheckForUpdates()
{
await Addressables.InitializeAsync().Task;
var checkHandle = Addressables.CheckForCatalogUpdates(false);
await checkHandle.Task;
if (checkHandle.Result.Count > 0)
{
var updateHandle = Addressables.UpdateCatalogs(checkHandle.Result);
await updateHandle.Task;
Addressables.Release(updateHandle);
}
Addressables.Release(checkHandle);
}