---
title: "Addressables 의 그룹 설정이 번들 모양을 정한다"
description: "Addressables 의 그룹은 에디터 개념이고 런타임 단위는 그룹 설정이 만든 번들입니다. 묶음 방식에 따라 같은 20개 에셋이 번들 1개, 20개, 4개가 되고, 그룹끼리 공유하는 에셋은 Analyze 로 찾아 따로 빼야 한 벌이 됩니다."
author: "유니얼"
pubDate: 2026-10-19
category: "game-dev/unity/runtime"
tags: ["Unity", "메모리", "최적화"]
canonical: https://blog.unialgames.com/posts/unity-addressables-groups/
---
<x-repo>
<script type="application/json">
{
  "repo": "SeoBYP/AssetBundleStudy",
  "text": "AssetBundle 과 Addressables 의 문서 내용을 Windows Player 에서 직접 재서 확인한 기록입니다.",
  "chips": ["Unity 6000.6.3f1", "Addressables 4.1.1", "Windows Player"],
  "links": [
    { "text": "결과 AD2 · AD3", "path": "Measure/results" },
    { "text": "그룹 구성 코드", "path": "Assets/Measure/Editor/MeasureSetup.cs" }
  ],
  "note": "묶음 방식별 로드 시간은 3회의 중앙값입니다. Analyze 전후 메모리는 한 번 잰 값입니다."
}
</script>
</x-repo>

Addressables 그룹 창에 에셋을 정리해 넣으면 할 일이 끝난 것 같습니다. 그런데 런타임에 올라오고 내려가는 것은 그룹이 아니라 번들이고, 같은 그룹이라도 설정 하나로 번들이 하나가 되기도 하고 스무 개가 되기도 합니다.

Unity 의 Addressables Q&A 는 이렇게 정리합니다. **그룹은 에디터 전용 개념이고, 런타임에는 번들 단위로 필요한 것만 올라온다.** 그래서 그룹 설정을 정하는 일이 곧 번들 모양을 정하는 일입니다.

## 묶음 방식이 번들 수를 정한다

그룹의 Bundle Mode 는 세 가지입니다.

- **Pack Together.** 그룹 전체를 번들 하나로
- **Pack Separately.** 엔트리마다 번들 하나씩
- **Pack Together By Label.** 같은 라벨끼리 번들 하나로

512×512 텍스처 20개(라벨 넷에 다섯 개씩)를 넣은 그룹을 세 방식으로 빌드하고, 텍스처 하나만 로드했습니다.

<x-compare>
<script type="application/json">
{
  "label": "같은 텍스처 20개, 하나만 로드할 때",
  "tabs": [
    { "label": "Pack Together", "text": "그룹 전체가 번들 하나입니다. 하나만 써도 큰 번들 하나를 엽니다.", "stats": [["번들", "1개, 14,552 KiB"], ["카탈로그", "8.7 KiB"], ["하나 로드", "49.6 ms"]] },
    { "label": "Pack Separately", "text": "에셋마다 번들입니다. 여는 번들은 작고, 카탈로그에 적을 것이 늘어납니다.", "stats": [["번들", "20개, 714~737 KiB"], ["카탈로그", "16.4 KiB"], ["하나 로드", "16.0 ms"]] },
    { "label": "By Label", "text": "라벨 넷이 번들 넷이 됩니다. 같은 라벨을 같이 쓰면 맞는 단위입니다.", "stats": [["번들", "4개, 약 3,600 KiB"], ["카탈로그", "9.8 KiB"], ["하나 로드", "22.6 ms"]] }
  ]
}
</script>
</x-compare>

세 방식 모두 **메모리에 올라온 텍스처는 요청한 하나뿐**이었습니다. 번들 안에서 에셋 하나만 꺼내는 것은 같고, 다른 것은 번들 크기와 수입니다. 번들이 클수록 하나를 꺼내는 시간이 늘었고, 번들을 쪼갤수록 카탈로그가 커져 20개일 때는 Pack Together 의 약 두 배였습니다. 로드 시간이 번들 크기에 따라 늘어난 원인은 확인하지 못했습니다.

내릴 때도 번들 단위라는 점이 더 중요합니다. 같은 번들의 에셋은 다 놓아야 번들이 내려가니, Q&A 의 권고대로 **같이 내려갈 것끼리 같은 번들로** 묶는 것이 기준이 됩니다. 한 화면에서 같이 쓰고 같이 버리는 것은 Pack Together 나 라벨로 묶고, 따로따로 쓰는 큰 에셋은 따로 뺍니다.

## 그룹끼리 공유하는 에셋은 그룹마다 복사된다

밑이 AssetBundle 이라서 공용 에셋 문제도 그대로 따라옵니다. 두 그룹의 프리팹이 같은 머티리얼을 쓰는데 그 머티리얼이 어느 그룹에도 없으면, 그룹마다의 번들에 복사됩니다. 이것을 찾는 것이 **Analyze** 창의 `Check Duplicate Bundle Dependencies` 규칙입니다.

`AD3_A`, `AD3_B` 그룹에 같은 머티리얼을 쓰는 프리팹을 하나씩 넣고 Analyze 를 돌렸습니다.

| | Analyze | 프리팹 번들 | 머티리얼 · native |
| --- | --- | --- | --- |
| 고치기 전 | 중복 11건 | 264.5 KiB 씩 | 2개 · +7.18 MiB |
| Fix 후 | No issues found | 3.6 KiB 씩, 격리 번들 262.9 KiB | 1개 · +5.82 MiB |

11건은 머티리얼 하나와 셰이더 셋(Lit, FallbackError, FallbackShader)이 두 그룹에 각각 잡힌 것, 그리고 다른 그룹의 셰이더 중복 셋입니다. **Fix** 를 누르면 `Duplicate Asset Isolation` 이라는 그룹을 새로 만들고 중복 에셋을 그리로 옮깁니다. 공용 에셋을 공용 번들에 적는 것을 자동으로 해 주는 셈입니다. 크기 대부분은 머티리얼이 아니라 URP 패키지의 셰이더였습니다.

Fix 결과를 그대로 두면 공용 에셋이 전부 한 번들에 모입니다. 그 번들은 공용 에셋을 쓰는 그룹 중 하나라도 살아 있는 동안 내려가지 않으니, 크면 그룹을 나눠 다시 정리합니다.

## 직접 확인하는 테스트 코드

그룹의 묶음 방식을 코드로 바꿔 빌드하고, 번들 수와 카탈로그 크기를 봅니다. 에디터 스크립트입니다.

```csharp
[MenuItem("Tools/Addressables/Build With Mode")]
static void BuildWithMode()
{
    var settings = AddressableAssetSettingsDefaultObject.Settings;
    var group = settings.FindGroup("AD2");
    var schema = group.GetSchema<BundledAssetGroupSchema>();

    foreach (var mode in new[]
    {
        BundledAssetGroupSchema.BundlePackingMode.PackTogether,
        BundledAssetGroupSchema.BundlePackingMode.PackSeparately,
        BundledAssetGroupSchema.BundlePackingMode.PackTogetherByLabel,
    })
    {
        schema.BundleMode = mode;
        AddressableAssetSettings.BuildPlayerContent(out AddressablesPlayerBuildResult result);
        long bytes = result.AssetBundleBuildResults
            .Where(b => b.SourceAssetGroup == group)
            .Sum(b => new FileInfo(b.FilePath).Length);
        int count = result.AssetBundleBuildResults.Count(b => b.SourceAssetGroup == group);
        Debug.Log($"{mode}: 번들 {count}개, {bytes / 1024.0:F1} KiB");
    }
}
```

Player 에서는 텍스처 하나를 로드한 뒤 같은 이름 규칙의 텍스처가 몇 장 올라왔는지 셉니다. 세 방식 모두 1이 나오고 번들 수만 1, 20, 4 로 달라지면 같은 결과입니다.

```csharp
var handle = Addressables.LoadAssetAsync<Texture2D>("AD2/Tex03");
yield return handle;
int alive = Resources.FindObjectsOfTypeAll<Texture2D>().Count(t => t.name.StartsWith("AD2_Tex"));
Debug.Log($"올라온 텍스처 {alive}장");
Addressables.Release(handle);
```

## 주의할 점

### 1. 같이 내려갈 것끼리 같은 번들로 묶는다

**안 지키면 생기는 문제.** 수명이 다른 에셋이 한 번들에 있으면, 하나라도 쓰는 동안 번들 전체가 열려 있고 이미 놓은 에셋도 같이 남습니다.

**이렇게 쓴다.** 화면이나 스테이지처럼 같이 올라오고 같이 버리는 단위로 그룹을 나눕니다. 그 안에서 따로 쓰는 큰 에셋은 Pack Separately 그룹으로 뺍니다.

### 2. 번들을 무작정 잘게 쪼개지 않는다

**안 지키면 생기는 문제.** 에셋마다 번들을 만들면 카탈로그가 커지고, Q&A 에 따르면 번들마다 붙는 메타데이터도 늘어납니다. 이 측정에서 20개로 쪼개자 카탈로그가 약 두 배가 됐습니다.

**이렇게 쓴다.** 하나씩 따로 쓰는 큰 에셋만 Pack Separately 로 두고, 작은 에셋은 같이 쓰는 단위로 묶습니다.

### 3. 빌드 전에 Analyze 로 중복을 확인한다

**안 지키면 생기는 문제.** 그룹끼리 공유하는 머티리얼과 셰이더가 그룹마다 복사돼 빌드 크기와 메모리가 늘어납니다. 그룹 창에는 안 보입니다.

**이렇게 쓴다.** 그룹을 바꿀 때마다 `Check Duplicate Bundle Dependencies` 를 돌리고, Fix 로 만든 격리 그룹이 너무 커지면 공용 에셋을 성격별로 나눠 다시 정리합니다.

## 정리

Addressables 에서 **올라오고 내려가는 단위는 그룹이 아니라 그룹 설정이 만든 번들입니다.**

- 같은 텍스처 20개가 Pack Together, Pack Separately, By Label 에 따라 번들 1개, 20개, 4개가 됐고, 어느 쪽이든 메모리에 올라온 것은 요청한 하나였습니다.
- 번들이 클수록 하나를 꺼내는 시간이 늘고, 잘게 쪼갤수록 카탈로그가 커집니다. 같이 내려갈 것끼리 묶습니다.
- 그룹끼리 공유하는 에셋은 그룹마다 복사되고, Analyze 의 Fix 가 격리 그룹으로 빼서 한 벌로 줄입니다.