제2장. 운영 단계의 에셋 비대화와 Project Auditor를 이용한 조사

Zaitsu Hiromu

주식회사 Sumzap

운영이 이어지는 프로젝트에서는 앱 용량과 메모리 사용량이 조금씩 증가합니다. 이 장에서는 대책을 알고 있는 팀에서도 비대화가 재발하는 이유와 이를 막는 방법, 그리고 계속 늘어나는 에셋을 찾아내는 수단을 다룹니다. 개별 에셋의 경량화 자체는 다루지 않습니다.

2.1. 운영 단계에서 비대화가 진행되는 이유

비대화는 일상적인 운영 속에서 조금씩 누적됩니다. 시즌 이벤트를 위해 추가된 고해상도 배너, 기간 한정 캐릭터의 보이스와 컷인, 콜라보 기획에서 받아들인 외부 제작 소재, 공지가 끝났는데도 남아 있는 캠페인용 에셋. 하나씩 보면 허용 범위 안이지만, 릴리스를 거듭하면 무시할 수 없는 양이 됩니다. 게다가 누적될수록 재검토 비용이 커지기 때문에 정리의 우선순위는 점점 낮아집니다. 원인은 기술보다 운영 규칙이 느슨해지는 데 있습니다. 운영 단계에서는 다음 네 가지가 반복해서 일어납니다.・규약이 낡아집니다: 기기와 요구 사항이 바뀌어 규약과 실태가 어긋나도 아무도 규약을 고쳐 쓰지 않습니다. 이번만이라며 통과시킨 예외가 쌓입니다.・확인이 허술해집니다: 마감이 다가오면 납품 소재 확인이 생략되고, 담당자가 교체될 때도 인수인계가 불완전하게 이루어집니다.・임시 대응이 계속 남습니다: 급하게 무압축 텍스처나 개별 출력 스프라이트를 넣은 채로 두고, 나중에 되돌리는 작업은 이루어지지 않습니다.・판단 기준이 기록되지 않습니다: 설정의 근거가 문서에 남아 있지 않아 담당자가 바뀌면 같은 기준을 재현할 수 없습니다. 어느 것도 도구를 도입하는 것만으로는 해결되지 않습니다.

2.2. 규약을 계속 운영한다

달성하고 싶은 지표를 정하고, 동작 보증 기기를 선택하고, 가장 부하가 큰 씬에서 검증합니다. 이 규약을 만드는 방법 자체는 전작 『Unity 퍼포먼스 튜닝 바이블』의 제1장에서 다룹니다. 운용 단계에서 문제가 되는 것은 규약을 정한 이후입니다. 규약은 정하는 즉시 실태와 어긋나기 시작합니다. 그래서 동작 보증 기기의 변경, Unity나 렌더링 파이프라인의 업데이트, 계측 방법의 변경과 같은 시점을 재검토 계기로 미리 정해 둡니다. 특히 계측 방법이 바뀌면 같은 에셋이라도 수치가 달라지므로, 계측 방법도 규약과 함께 남겨 둡니다. 규약의 수치는 익스포트, 임포트, 자동 빌드 중 어느 한 곳에서 검사가 실행되도록 합니다. 중단할지 통과시킬지는 항목별로 정하되, 통과시키는 경우에도 실측값을 빌드 로그나 리포트로 팀 전원이 볼 수 있는 곳에 남기십시오. 본인 화면에만 경고를 표시하는 방식은 그냥 넘어가기 쉽습니다. 규약을 초과한 에셋의 수정은 값을 고친다고 끝나지 않습니다. 압축 설정을 바꿀 때는 겉모습이 허용 범위에 들어오는지, 번들을 재구성할 때는 참조가 끊어지지 않았는지를 실제 서비스와 같은 조건에서 확인해야 합니다. 전작이 경고했듯이 양산 후의 재작업은 발주부터 품질 검사, 디버그까지 포함하는 공정입니다. 한꺼번에 고치기보다 릴리스마다 계측하여 늘어난 만큼을 그때그때 수정하는 것이 이상적입니다.

2.3. 비대화 패턴 분류

소재 종류별로 대책을 정리하면 어떤 소재가 무거운지는 알 수 있어도 왜 무거워졌는지까지는 알 수 없습니다. 원인이 남아 있으면 같은 비대화가 재발합니다. 그래서 소재 종류를 가로질러 원인별로 여섯 가지로 분류합니다.

표 2.1: 비대화의 6가지 패턴

패턴무슨 일이 일어나고 있는가
압축 설정 오류임포트 설정이 비압축이나 기본값인 채로 방치되어 필요한 용량의 몇 배를 차지합니다
과도한 해상도최대 해상도를 지정하지 않고 가져와 면적에 비례하여 늘어납니다
불필요한 부수 데이터사용하지 않는 보조 데이터를 활성화한 채로 포함시켜 메모리에도 유지합니다
형식 선택 오류용도나 플랫폼에 맞지 않는 포맷을 골라 용량을 더 쓰거나, 실행 시에 압축이 풀려 메모리를 소비합니다
묶는 방식의 불일치Sprite Atlas나 번들을 묶는 방식이 실제 사용 단위와 맞지 않아, Sprite 한 장을 표시하는데 아틀라스 전체를 로드하는 등 사용하지 않는 것까지 함께 로드합니다
번들 간 중복공유 에셋을 등록하지 않고 참조하여 참조하는 번들의 수만큼 포함됩니다

앞의 네 가지는 에셋 임포트 시점에 판정할 수 있지만, 뒤의 두 가지는 다른 에셋과의 관계로 결정되므로 그 시점에는 판정할 수 없습니다. 이 차이가 다음 절에서 대책을 두 단계로 나누는 이유입니다.

2.4. 임포트 시 자동 적용과 빌드 전 검사

재발을 막으려면 에셋 임포트 시 올바른 설정을 적용하고, 그것을 빠져나간 것을 빌드 전에 찾아냅니다. 자동 적용 수단은 두 가지입니다. 조건에 따라 값을 바꿔야 한다면 임포트 전후에 처리를 끼워 넣을 수 있는 AssetPostprocessor를 사용합니다. 타입별 초기값을 고정하기만 하면 된다면 Preset으로 충분합니다. 다만 임포트 시 적용만으로는 누락이 생깁니다. .meta 파일째로 반입된 에셋은 설정을 유지한 채 들어오며, 앞 절의 뒤쪽 두 패턴은 이 단계에서는 판정할 수 없습니다. 따라서 빌드 전이나 자동 빌드 단계에서 규약에 어긋나는 에셋이 섞여 있지 않은지 검사합니다. 텍스처의 최대 해상도나 메시의 폴리곤 수 같은 제한 규약을 테스트로 작성해 두면 에디터와 자동 빌드 양쪽에서 같은 기준을 사용할 수 있습니다. AssetRegulationManager처럼 이 용도의 OSS도 공개되어 있습니다*1. 이러한 검사를 구조화하지 않고 규약을 문서에 적어 공지하기만 하는 운영은, 앞에서 든 규약이 낡아지는 상태와 판단 기준이 남지 않는 상태를 그대로 초래합니다. 규칙을 정하는 것은 사람의 일이지만, 지키게 하는 부분은 기계에 맡기십시오.

2.5. 번들 간 중복이 발생하는 구조

여섯 패턴 중 가장 눈에 띄지 않는 것이 번들 간 중복입니다. 원인이 개별 에셋의 설정이 아니라 에셋 간의 참조 관계에 있기 때문입니다. Addressables는 에셋을 그룹 단위로 관리하고, 빌드 시 그룹별 번들로 묶습니다. 이때 Addressable에 등록하지 않은 에셋은 암묵적 의존성으로 취급되어, 이를 참조하는 번들 각각에 복제됩니다.

등록하지 않은 공유 에셋의 복제(위)와 전용 그룹에 등록한 경우(아래)

그림 2.1: 등록하지 않은 공유 에셋의 복제(위)와 전용 그룹에 등록한 경우(아래)

그림의 예에서는 4MB 텍스처를 두 Prefab이 참조하는 것만으로 번들 합계가 10MB가 됩니다. 이 텍스처를 전용 그룹에 등록하여 명시적 의존성으로 만들면 복제가 해소되어 합계가 6MB까지 내려갑니다. 참조하는 쪽이 늘어나면 그 수만큼 복제되고, 동시에 로드하면 메모리에도 같은 만큼 펼쳐지므로 방치할수록 영향이 커집니다. 참고로 실제 번들은 압축되므로 수치는 구조를 보여 주는 대략적인 값입니다. 이러한 중복은 눈으로는 다 찾을 수 없으므로 도구로 검출합니다. Addressables에서는 Addressables Analyze*2를 사용할 수 있습니다(2.0 계열에서 일시적으로 삭제되었다가 2.3.1에서 복구되었습니다). 검출된 중복을 자동으로 해소하는 기능도 있지만 그룹 구성이 바뀌므로, 적용 후에는 빌드 결과까지 확인하십시오.

2.6. 비대해진 에셋을 조사한다

규약과 검사로 새로운 비대화는 막을 수 있지만, 이미 쌓여 있는 에셋은 별도로 찾아내야 합니다. 에셋 프로파일링에는 용도가 다른 도구가 여러 가지 있습니다.

표 2.2: 용량과 메모리 조사에 사용하는 도구

도구알 수 있는 것
Build Report / Editor Log빌드 크기의 카테고리별 내역
Addressables AnalyzeAddressables의 중복 번들 의존성 검출 및 수정
Project Auditor프로젝트 전체의 임포트 설정과 정적 구성 문제
Memory Profiler실행 시 메모리 사용량과 오브젝트의 참조 관계

이 중 Memory Profiler는 전작의 3장 「프로파일링 도구」에서 다룹니다. 이 장에서는 전작에서 소개하지 않은 Project Auditor를 다룹니다.

2.7. Project Auditor로 찾아낸다

Project Auditor는 프로젝트 내의 에셋, 코드, 설정을 정적으로 분석하여 문제가 있는 부분을 목록으로 출력하는 도구입니다. 규약으로 정리할 여력이 없는 단계에서도 무엇이 문제가 될 수 있는지 파악할 수 있습니다. 오랫동안 실험 단계 패키지였으나 2025년 2월에 1.0이 릴리스되어 정식 버전이 되었습니다. 이후의 화면과 항목은 Unity 6.4와 Rules 패키지 1.0.3에서 확인한 것입니다.

2.7.1. 도입 방법은 Unity 버전에 따라 다르다

Unity 6.4 이전에서는 Package Manager에서 com.unity.project-auditor를 추가합니다*3. 6.4 이후에는 에디터에 포함되어 추가할 필요가 없지만*4, 판정에 사용하는 규칙이 com.unity.project-auditor-rules로 분리되었으므로 이를 도입하지 않으면 분석할 수 없습니다(그림 2.2).

Rules 패키지. 분석 본체는 에디터의 모듈로 존재한다

그림 2.2: Rules 패키지. 분석 본체는 에디터의 모듈로 존재한다

규칙을 본체에서 분리함으로써 에디터 버전을 올리지 않고도 규칙만 업데이트할 수 있습니다.

2.7.2. Assets 뷰 사용법

Window > Analysis > Project Auditor를 열어 분석을 실행하면 결과는 Summary, Code, Assets, Shaders, Project, Build 뷰로 나뉩니다(뷰는 Unity 버전에 따라 늘어날 수 있습니다). 용량과 메모리 조사에 사용하는 것은 Assets 뷰로, Asset Issues, Textures, Sprite Atlases 등 아홉 개로 나뉘어 있습니다. 처음 여는 것은 Asset Issues입니다(그림 2.3). 검출된 문제가 종류별로 묶여 각각 몇 건 발견되었는지 표시됩니다.

Asset Issues 뷰. 검증용으로 준비한 프로젝트에서의 검출 예

그림 2.3: Asset Issues 뷰. 검증용으로 준비한 프로젝트에서의 검출 예

종류를 펼치면 개별 에셋이 표시되며, 선택하면 오른쪽에 상세 내용과 권장 대처가 나옵니다. 전체 모습을 파악했다면 Textures 같은 개별 뷰에서 그 내역을 봅니다(그림 2.4).

Textures 뷰. 설정과 결과 크기가 가로로 나란히 표시된다

그림 2.4: Textures 뷰. 설정과 결과 크기가 가로로 나란히 표시된다

이 뷰의 장점은 설정과 결과가 같은 행에 나란히 표시된다는 점입니다. 같은 2048×2048 텍스처라도 Compressed 행은 2.7MB, Uncompressed 행은 16.0MB를 차지합니다. 설정 한 곳의 차이로 6배 가까운 차이가 나는 것을 Inspector를 열지 않고도 알 수 있습니다. Size 열을 내림차순으로 정렬하고 상위부터 Compression, Resolution, Format을 확인하면 압축 설정 오류, 과도한 해상도, 형식 선택 오류를 찾을 수 있습니다.

2.7.3. 검출 결과를 줄인다

운영 중인 프로젝트에서 분석을 실행하면 검출 결과가 수천 건을 넘기도 합니다. 이 상태에서 위에서부터 처리하려 해도 진행되지 않습니다. 앞서 나온 그림 2.3에 있는 Filters로 표시를 좁힙니다. Only Major/Critical에 체크하면 중요도가 높은 것만 남고, Areas에서 대상 영역을 고르면 용량과 관련된 지적만 표시할 수 있습니다. 검출된 문제에는 중요도가 붙습니다. 문서에는 Major, Moderate, Minor, Ignored의 네 종류로 설명되어 있지만, 정의상으로는 Critical도 존재합니다. Ignored는 중요도 단계가 아니라 무시하도록 지정한 상태를 가리킵니다. 대처는 Major부터 순서대로 진행하며, Critical이 검출된 경우에는 이를 최우선으로 처리합니다. 정적 분석에서는 의도한 설정도 지적되므로 한 건씩 확인한 뒤 고치는 것이 안전합니다. 오탐으로 판단한 지적에는 Ignore를 지정합니다. Ignore는 열려 있는 리포트에 기록되는 상태이므로 설정 파일에는 기록되지 않으며, 분석을 다시 실행하면 해제됩니다. 검출 임곗값 같은 판정 파라미터는 ProjectSettings/ProjectAuditorSettings.asset에 저장되므로, 이쪽은 커밋하면 모두가 같은 값으로 맞출 수 있습니다. 지적을 지속적으로 억제하고 싶다면 자동 빌드 쪽 스크립트에서 AnalysisParams.WithAdditionalDiagnosticRules에 비활성화 규칙을 전달합니다.

2.7.4. 자동 빌드에 통합한다

Project Auditor는 커맨드 라인에서도 실행할 수 있습니다*5. 자동 빌드에 통합하여 검출 건수를 릴리스마다 남겨 두면 어느 릴리스에서 늘었는지 추적할 수 있습니다. Preferences에는 빌드 후에 검출 건수를 로그로 출력하는 설정과 검출을 에러로 취급하는 설정이 있습니다. 실패 판정을 직접 작성하기 전에 이쪽으로 충분한지 확인하십시오. 한편 저장한 두 리포트를 비교하는 API는 제공되지 않으므로, 이전과의 차이를 구하려면 직접 처리를 구현해야 합니다. 또한 빌드 후 자동 분석이 완료되지 않고 멈춘 채로 있거나, 분석 중에 메모리를 모두 소진한다는 보고도 있습니다*6. 타임아웃을 설정하여 분석 실패가 빌드 전체를 멈추지 않도록 하십시오.

2.8. 마치며

비대화 대책은 개별 에셋을 가볍게 하는 기술보다 팀으로서 재발을 막는 구조를 만드는 데 비중이 큰 주제입니다. 운영 중에 규약이 느슨해지는 것 자체는 어느 프로젝트에서나 일어납니다. 그렇기 때문에 기준을 정하고 재검토하는 데 사람의 시간을 쓰고 지키게 하는 부분은 기계에 맡기는 방식이 결국 가장 오래 지속된다고 생각합니다. Project Auditor는 막 정식 버전이 된 도구이지만, 규약 작성까지 손이 미치지 못한 프로젝트가 현황을 파악하는 입구로서 충분히 실용적입니다. 우선 한 번 분석을 실행하여 자신들의 프로젝트 경향을 살펴보는 것부터 시작해 보십시오.