Unity 게임에서 LMK를 해결하는 것은 체계적인 프로세스입니다.
메모리 스냅샷 가져오기
Unity 프로파일러를 사용하여 Unity에서 관리하는 메모리 스냅샷을 가져옵니다. 그림 2는 Unity에서 게임의 메모리를 처리하는 데 사용하는 메모리 관리 레이어를 보여줍니다.
관리형 메모리
Unity의 메모리 관리는 관리형 힙과 가비지 컬렉터를 사용하여 메모리를 자동으로 할당하고 할당하는 제어된 메모리 레이어를 구현합니다. 관리형 메모리 시스템은 C# 스크립팅 환경으로 Mono 또는 IL2CPP를 기반으로 합니다. 관리형 메모리 시스템의 이점은 가비지 컬렉터를 활용하여 메모리 할당을 자동으로 해제한다는 것입니다.
C# 관리되지 않는 메모리
관리되지 않는 C# 메모리 레이어는 네이티브 메모리 레이어에 대한 액세스를 제공하여 C# 코드를 사용하는 동안 메모리 할당을 정밀하게 제어할 수 있도록 합니다. 이 메모리 관리 레이어는 Unity.Collections 네임스페이스와 UnsafeUtility.Malloc 및 UnsafeUtility.Free와 같은 함수를 통해 액세스할 수 있습니다.
네이티브 메모리
Unity의 내부 C/C++ 코어는 네이티브 메모리 시스템을 사용하여 장면, 애셋, 그래픽 API, 드라이버, 하위 시스템, 플러그인 버퍼를 관리합니다. 직접 액세스는 제한되지만 Unity의 C# API로 데이터를 안전하게 조작하고 효율적인 네이티브 코드를 활용할 수 있습니다. 네이티브 메모리는 직접 상호작용이 거의 필요하지 않지만 프로파일러를 사용하여 성능에 미치는 네이티브 메모리 영향을 모니터링하고 설정을 조정하여 성능을 최적화할 수 있습니다.
그림 3과 같이 메모리는 C# 과 네이티브 코드 간에 공유되지 않습니다. C# 에 필요한 데이터는 필요할 때마다 관리형 메모리 공간에 할당됩니다.
관리형 게임의 코드 (C#)가 엔진의 네이티브 메모리 데이터에 액세스하려면 예를 들어 GameObject.transform 호출은 네이티브 호출을 통해 네이티브 영역의 메모리 데이터에 액세스한 다음 Bindings를 사용하여 값을 C#으로 반환합니다. 바인딩은 각 플랫폼의 적절한 호출 규칙을 보장하고 관리형 유형을 네이티브에 상응하는 유형으로 자동 마샬링합니다.
_transform_ 속성에 액세스하기 위한 관리형 셸이 네이티브 코드에 보존되므로 이 작업은 처음 한 번만 실행됩니다. transform 속성을 캐싱하면 관리형 코드와 네이티브 코드 간의 왕복 호출 수를 줄일 수 있지만 캐싱의 유용성은 속성이 사용되는 빈도에 따라 다릅니다. 또한 이러한 API에 액세스할 때 Unity는 네이티브 메모리의 일부를 관리형 메모리에 복사하지 않습니다.
자세한 내용은 Unity의 메모리 소개를 참고하세요.
또한 메모리 예산을 설정하는 것은 게임을 원활하게 실행하는 데 매우 중요하며 메모리 소비 분석 또는 보고 시스템을 구현하면 각 새 출시 버전이 메모리 예산을 초과하지 않도록 할 수 있습니다. 지속적 통합 (CI)과 Play 모드 테스트를 통합하여 게임의 특정 영역에서 메모리 소비를 확인하는 것도 더 나은 통계를 얻기 위한 또 다른 전략입니다.
애셋 관리
이는 메모리 소비에서 가장 영향력 있고 실행 가능한 부분입니다. 가능한 한 빨리 프로파일링하세요.
Android 게임의 메모리 사용량은 게임 유형, 애셋 수 및 유형, 메모리 최적화 전략에 따라 크게 달라질 수 있습니다. 그러나 메모리 사용량에 일반적으로 영향을 미치는 요소로는 텍스처, 메시, 오디오 파일, 셰이더, 애니메이션, 스크립트가 있습니다.
중복 애셋 감지
첫 번째 단계는 메모리 프로파일러, 빌드 보고서 도구 또는 프로젝트 감사자를 사용하여 잘못 구성된 애셋과 중복된 애셋을 감지하는 것입니다.
텍스처
게임의 기기 지원을 분석하고 올바른 텍스처 형식을 결정합니다. Play Asset Delivery, Addressable 또는 AssetBundle을 사용하는 수동 프로세스를 사용하여 고급 기기와 저가형 기기의 텍스처 번들을 분할할 수 있습니다.
모바일 게임 성능 최적화 및 Unity 텍스처 가져오기 설정 최적화 토론 게시물에서 제공되는 가장 잘 알려진 권장사항을 따르세요. 그런 다음 다음 해결 방법을 시도해 보세요.
ASTC 형식으로 텍스처를 압축하여 메모리 사용 공간을 줄이고 8x8과 같은 더 높은 블록 비율을 실험해 보세요.
ETC2를 사용해야 하는 경우 텍스처를 Atlas에 패킹합니다. 여러 텍스처를 단일 텍스처에 배치하면 2의 거듭제곱 (POT)이 보장되고, 그리기 호출을 줄일 수 있으며, 렌더링 속도를 높일 수 있습니다.
RenderTarget 텍스처 형식과 크기를 최적화합니다. 불필요하게 높은 해상도의 텍스처는 피하세요. 모바일 기기에서 더 작은 텍스처를 사용하면 메모리가 절약됩니다.
텍스처 채널 패킹을 사용하여 텍스처 메모리를 절약합니다.
메시 및 모델
기본 설정 (27페이지)을 확인하고 다음 메시 가져오기 설정을 확인합니다.
- 중복되고 더 작은 메시를 병합합니다.
- 장면의 객체 (예: 정적 객체 또는 원격 객체)의 꼭짓점 수를 줄입니다.
- 고지오메트리 애셋의 세부정보 수준 (LOD) 그룹을 생성합니다.
머티리얼 및 셰이더
- 빌드 프로세스 중에 프로그래매틱 방식으로 사용되지 않는 셰이더 배리언트를 스트리핑합니다.
- 셰이더 중복을 방지하기 위해 자주 사용되는 셰이더 배리언트를 uber 셰이더로 통합합니다.
- 동적 셰이더 로드를 사용 설정하여 VRAM/RAM에서 미리 로드된 셰이더의 큰 메모리 사용 공간을 해결합니다. 그러나 셰이더 컴파일로 인해 프레임이 끊기는 경우 주의하세요.
- 동적 셰이더 로드를 사용하여 모든 배리언트가 로드되지 않도록 합니다. 자세한 내용은 셰이더 빌드 시간 및 메모리 사용량 개선 블로그 게시물을 참고하세요.
MaterialPropertyBlocks를 활용하여 머티리얼 인스턴스를 올바르게 사용합니다.
오디오
기본 설정 (41페이지)을 확인하고 다음 메시 가져오기 설정을 확인합니다.
- FMOD 또는 Wwise와 같은 서드 파티 오디오 엔진을 사용할 때 사용되지 않거나 중복된
AudioClip참조를 삭제합니다. - 오디오 데이터를 미리 로드합니다. 런타임 또는 장면 시작 중에 즉시 필요하지 않은 클립의 미리 로드를 사용 중지합니다. 이렇게 하면 장면 초기화 중에 메모리 오버헤드를 줄일 수 있습니다.
애니메이션
- Unity의 애니메이션 압축 설정을 조정하여 키프레임 수를 최소화하고 중복 데이터를 삭제합니다.
- 키프레임 감소: 불필요한 키프레임을 자동으로 삭제합니다.
- 쿼터니언 압축: 회전 데이터를 압축하여 메모리 사용량을 줄입니다.
애니메이션 가져오기 설정 의 리그 또는 애니메이션 탭에서 압축 설정을 조정할 수 있습니다.
여러 객체의 애니메이션 클립을 복제하는 대신 애니메이션 클립을 재사용합니다.
Animator 재정의 컨트롤러를 사용하여 Animator 컨트롤러를 재사용하고 여러 캐릭터의 특정 클립을 바꿉니다.
물리 기반 애니메이션 베이킹: 애니메이션이 물리 기반 또는 절차적이라면 런타임 계산을 방지하기 위해 애니메이션 클립으로 베이킹합니다.
스켈레톤 리그 최적화: 리그에서 더 적은 수의 뼈를 사용하여 복잡성과 메모리 소비를 줄입니다.
- 작거나 정적인 객체에 과도한 뼈를 사용하지 마세요.
- 특정 뼈가 애니메이션 처리되지 않거나 필요하지 않은 경우 리그에서 삭제합니다.
애니메이션 클립 길이를 줄입니다.
- 필요한 프레임만 포함하도록 애니메이션 클립을 트리밍합니다. 사용되지 않거나 지나치게 긴 애니메이션을 저장하지 마세요.
- 반복되는 동작을 위한 긴 클립을 만드는 대신 루핑 애니메이션을 사용합니다.
애니메이션 구성요소가 하나만 연결되거나 활성화되도록 합니다. 예를 들어, Animator를 사용하는 경우 기존 애니메이션 구성요소를 사용 중지하거나 삭제합니다.
Animator가 불필요한 경우 사용하지 마세요. 간단한 VFX의 경우 트위닝 라이브러리를 사용하거나 스크립트에서 시각적 효과를 구현합니다. 애니메이터 시스템은 특히 저가형 모바일 기기에서 리소스를 많이 사용할 수 있습니다.
많은 수의 애니메이션을 처리할 때는 애니메이션에 작업 시스템을 사용합니다. 이 시스템은 메모리 효율성을 높이기 위해 완전히 재설계되었습니다.
장면
새 장면이 로드되면 애셋이 종속 항목으로 가져옵니다. 그러나 적절한 애셋 수명 주기 관리가 없으면 이러한 종속 항목 은 참조 카운터로 모니터링되지 않습니다. 결과적으로 사용되지 않는 장면이 언로드된 후에도 애셋이 메모리에 남아 메모리 조각화를 일으킬 수 있습니다.
- Unity의 객체 풀링을 사용하여 반복되는 게임플레이 요소의 GameObject 인스턴스를 재사용합니다. 객체 풀링은 스택을 사용하여 재사용을 위한 객체 인스턴스 모음을 보유하며 스레드로부터 안전하지 않기 때문입니다.
Instantiate및Destroy를 최소화하면 CPU 성능과 메모리 안정성이 모두 개선됩니다. - 애셋 언로드:
- 스플래시 화면 또는 로드 화면과 같이 중요하지 않은 순간에 전략적으로 애셋을 언로드합니다.
Resources.UnloadUnusedAssets를 자주 사용하면 대규모 내부 종속 항목 모니터링 작업으로 인해 CPU 처리가 급증합니다.- GC.MarkDependencies
프로필 마커에서 큰 CPU 급증을 확인합니다.
실행 빈도를 삭제하거나 줄이고, 포괄적인
Resources.UnloadUnusedAssets()에 의존하는 대신 Resources.UnloadAsset을 사용하여 특정 리소스를 수동으로 언로드합니다.
- Resources.UnloadUnusedAssets를 지속적으로 사용하는 대신 장면을 재구성합니다.
-
Addressables에Resources.UnloadUnusedAssets()를 호출하면 동적으로 로드된 번들이 의도치 않게 언로드될 수 있습니다. 동적으로 로드된 애셋의 수명 주기를 신중하게 관리합니다.
기타
장면 전환으로 인한 조각화 - 메서드
Resources.UnloadUnusedAssets()가 호출되면 Unity는 다음 작업을 실행합니다.- 더 이상 사용되지 않는 애셋의 메모리를 해제합니다.
- 가비지 컬렉터와 유사한 작업을 실행하여 관리형 및 네이티브 객체 힙에서 사용되지 않는 애셋을 확인하고 언로드합니다.
- 활성 참조가 없는 경우 텍스처, 메시, 애셋 메모리를 정리합니다.
AssetBundle또는Addressable\- 이 영역에서 변경하는 것은 복잡하며 전략을 구현하기 위해 팀의 공동 노력이 필요합니다. 그러나 이러한 전략을 숙지하면 메모리 사용량이 크게 개선되고, 다운로드 크기가 줄어들며, 클라우드 비용이 절감됩니다. Unity에서 애셋 관리에 관한 자세한 내용은Addressables를 참고하세요.중앙 집중식 공유 종속 항목 &mdash: 셰이더, 텍스처, 글꼴과 같은 공유 종속 항목을 전용 번들 또는
Addressable그룹으로 체계적으로 그룹화합니다. 이렇게 하면 중복이 줄어들고 불필요한 애셋이 효율적으로 언로드됩니다.종속 항목 추적에
Addressables사용 - Addressables 는 로드 및 언로드를 간소화하며 더 이상 참조되지 않는 종속 항목을 자동으로 언로드할 수 있습니다. 콘텐츠 관리 및 종속 항목 해결을 위해Addressables로 전환하는 것은 게임의 특정 사례에 따라 실행 가능한 해결 방법이 될 수 있습니다. 분석 도구로 종속 항목 체인을 분석하여 불필요한 중복 또는 종속 항목을 식별합니다. 또는 AssetBundle을 사용하는 경우 Unity 데이터 도구를 참고하세요.TypeTrees- 게임의Addressables및AssetBundles가 플레이어와 동일한 버전의 Unity를 사용하여 빌드 및 배포되고 다른 플레이어 빌드와의 이전 버전과의 호환성이 필요하지 않은 경우 쓰기TypeTree를 사용 중지하는 것이 좋습니다. 이렇게 하면 번들 크기와 직렬화된 파일 객체 메모리 사용 공간이 줄어듭니다. 로컬 Addressables 패키지 설정에서 ContentBuildFlags를 DisableWriteTypeTree로 설정하여 빌드 프로세스를 수정합니다.
가비지 컬렉터 친화적인 코드 작성
Unity는 가비지 컬렉션 (GC)을 활용하여 사용되지 않는 메모리를 자동으로 식별하고 해제하여 메모리를 관리합니다. GC는 필수적이지만 이 프로세스는 게임을 일시적으로 일시중지하여 성능 문제 (예: 프레임 속도 급증)와 최적화되지 않은 사용자 환경을 초래할 수 있으므로 제대로 처리하지 않으면 성능 문제가 발생할 수 있습니다.
관리형 힙 할당 빈도를 줄이는 데 유용한 기법은 Unity 매뉴얼을 참고하고 예는 UnityPerformanceTuningBible 271페이지를 참고하세요.
가비지 컬렉터 할당 줄이기:
- 힙 메모리를 할당하는 LINQ, 람다, 클로저를 피합니다.
- 문자열 연결 대신 변경 가능한 문자열에
StringBuilder를 사용합니다. - 컬렉션을 다시 인스턴스화하는 대신
COLLECTIONS.Clear()를 호출하여 컬렉션을 재사용합니다.
UI 캔버스 업데이트 관리:
- UI 요소의 동적 변경 - 텍스트, 이미지 또는
RectTransform속성과 같은 UI 요소가 업데이트되면 (예: 텍스트 콘텐츠 변경, 요소 크기 조절, 위치 애니메이션 처리) 엔진은 임시 객체에 메모리를 할당할 수 있습니다. - 문자열 할당 - 문자열은 대부분의 프로그래밍 언어에서 변경할 수 없으므로 텍스트와 같은 UI 요소에는 문자열 업데이트가 필요한 경우가 많습니다.
- 더티 캔버스 - 캔버스에서 무언가가 변경되면 (예: 크기 조절, 요소 사용 설정 및 중지, 레이아웃 속성 수정) 전체 캔버스 또는 일부가 더티 로 표시되고 다시 빌드될 수 있습니다. 이렇게 하면 가비지 생성을 추가하는 임시 데이터 구조 (예: 메시 데이터, 꼭짓점 버퍼, 레이아웃 계산)가 생성될 수 있습니다.
- 복잡하거나 빈번한 업데이트 - 캔버스에 많은 수의 요소가 있거나 자주 업데이트되는 경우 (예: 모든 프레임) 이러한 재빌드로 인해 상당한 메모리 급변이 발생할 수 있습니다.
- UI 요소의 동적 변경 - 텍스트, 이미지 또는
증분 GC를 사용 설정하여 여러 프레임에 할당 정리 작업을 분산하여 대규모 컬렉션 급증을 줄입니다. 프로파일링하여 이 옵션이 게임의 성능과 메모리 사용 공간을 개선하는지 확인합니다.
게임에 제어된 접근 방식이 필요한 경우 가비지 컬렉션 모드를 수동으로 설정합니다. 그런 다음 레벨 변경 시 또는 활성 게임플레이가 없는 다른 순간에 가비지 컬렉션을 호출합니다.
게임 상태 전환(예: 레벨 전환)을 위해 수동 가비지 컬렉션 GC.Collect() 호출을 호출합니다.
간단한 코드 관행부터 시작하여 필요에 따라 네이티브 배열 또는 대규모 배열의 다른 네이티브 컨테이너를 사용하여 배열을 최적화합니다.
Unity 메모리 프로파일러와 같은 도구를 사용하여 관리형 객체를 모니터링하여 삭제 후에도 지속되는 관리되지 않는 객체 참조를 추적합니다.
메모리 누수 및 조각화 방지
메모리 누수
C# 코드에서 객체가 삭제된 후에도 Unity 객체에 대한 참조가 있으면 관리형 셸이라고 하는 관리형 래퍼 객체가 메모리에 남아 있습니다. 참조와 연결된 네이티브 메모리는 장면이 언로드되거나 메모리가 연결된 GameObject 또는 상위 객체가 Destroy() 메서드를 통해 삭제될 때 해제됩니다. 그러나 장면 또는 GameObject에 대한 다른 참조가 삭제되지 않은 경우 관리형 메모리가 누출된 셸 객체로 유지될 수 있습니다. 관리형 셸 객체에 관한 자세한 내용은
관리형 셸 객체 매뉴얼을 참고하세요.
또한 메모리 누수는 이벤트 구독, 람다 및 클로저, 문자열 연결, 풀링된 객체의 부적절한 관리로 인해 발생할 수 있습니다.
- 시작하려면 Unity 메모리 스냅샷을 올바르게 비교하기 위한 메모리 누수 찾기를 참고하세요.
- 이벤트 구독 및 메모리 누수를 확인합니다. 객체가 이벤트(예: 대리자 또는 UnityEvents)를 구독하지만 삭제되기 전에 제대로 구독 취소하지 않으면 이벤트 관리자 또는 게시자가 이러한 객체에 대한 참조를 유지할 수 있습니다. 이렇게 하면 이러한 객체가 가비지 컬렉션되지 않아 메모리 누수가 발생합니다.
- 객체 삭제 시 등록 취소되지 않은 전역 또는 싱글톤 클래스 이벤트를 모니터링합니다. 예를 들어 객체 소멸자에서 대리자를 구독 취소하거나 연결 해제합니다.
- 풀링된 객체를 삭제하면 텍스트 메시 구성요소, 텍스처, 상위 GameObjects에 대한 참조가 완전히 무효화됩니다.
- Unity 메모리 프로파일러 스냅샷을 비교하고 명확한 이유 없이 메모리 소비의 차이를 관찰할 때 차이는 그래픽 드라이버 또는 운영체제 자체로 인해 발생할 수 있습니다.
메모리 조각화
메모리 조각화는 많은 작은 할당이 임의의 순서로 해제될 때 발생합니다. 힙 할당은 순차적으로 이루어지므로 이전 청크의 공간이 부족하면 새 메모리 청크가 생성됩니다. 따라서 새 객체는 이전 청크의 빈 영역을 채우지 않아 조각화가 발생합니다. 또한 대규모 임시 할당은 게임 세션 기간 동안 영구적인 조각화를 일으킬 수 있습니다.
이 문제는 수명이 짧은 대규모 할당이 수명이 긴 할당 근처에서 이루어질 때 특히 문제가 됩니다.
수명에 따라 할당을 그룹화합니다. 이상적으로는 수명이 긴 할당을 애플리케이션 수명 주기의 초기에 함께 실행해야 합니다.
관찰자 및 이벤트 관리자
- 메모리 누수 섹션에서 언급한 문제 외에도 시간이 지남에 따라 메모리 누수는 더 이상 사용되지 않는 객체에 할당된 사용되지 않는 메모리를 남겨 조각화에 기여할 수 있습니다.
- 풀링된 객체를 삭제하면
텍스트 메시 구성요소, 텍스처, 상위
GameObjects에 대한 참조가 완전히 무효화됩니다. - 이벤트 관리자는 이벤트 구독을 관리하기 위해 목록 또는 사전을 만들고 저장하는 경우가 많습니다. 이러한 항목이 런타임 중에 동적으로 증가하고 감소하면 빈번한 할당 및 할당 해제로 인해 메모리 조각화에 기여할 수 있습니다.
코드
- 코루틴은 때때로 메모리를 할당합니다. 이는 매번 새 코루틴을 선언하는 대신 IEnumerator의 return 문을 캐싱하여 쉽게 피할 수 있습니다.
- 풀링된 객체의 수명 주기 상태를 지속적으로 모니터링하여
UnityEngine.Object고스트 참조를 유지하지 않도록 합니다.
애셋
- 텍스트 기반 게임 환경에 동적 대체 시스템을 사용하여 다국어 사례의 모든 글꼴을 미리 로드하지 않도록 합니다.
- 애셋 (예: 텍스처 및 파티클)을 유형 및 예상 수명 주기에 따라 함께 구성합니다.
- 중복 UI 이미지 및 정적 메시와 같이 유휴 수명 주기 속성이 있는 애셋을 압축합니다.
수명 기반 할당
- 애플리케이션 수명 주기의 시작 부분에 수명이 긴 애셋을 할당하여 컴팩트한 할당을 보장합니다.
- 메모리 집약적 또는 일시적인 데이터 구조 (예: 물리 클러스터)에 NativeCollections 또는 커스텀 할당자를 사용합니다.
코드 관련 및 실행 파일 메모리 작업
게임 실행 파일과 플러그인도 메모리 사용량에 영향을 미칩니다.
IL2CPP 메타데이터
IL2CPP는 빌드 시 모든 유형 (예: 클래스, 제네릭, 대리자)의 메타데이터를 생성하며, 이 메타데이터는 런타임에 리플렉션, 유형 검사, 기타 런타임 관련 작업에 사용됩니다. 이 메타데이터는 메모리에 저장되며 애플리케이션의 총 메모리 사용 공간에 상당한 영향을 미칠 수 있습니다. IL2CPP의 메타데이터 캐시는 초기화 및 로드 시간에 상당한 영향을 미칩니다. 또한 IL2CPP는 특정 메타데이터 요소 (예: 제네릭 유형 또는 직렬화된 정보)를 중복 삭제하지 않으므로 메모리 사용량이 늘어날 수 있습니다. 이는 프로젝트에서 반복되거나 중복된 유형 사용으로 인해 악화됩니다.
IL2CPP 메타데이터는 다음을 통해 줄일 수 있습니다.
- 리플렉션 API는 IL2CPP 메타데이터 할당에 상당한 영향을 미칠 수 있으므로 사용하지 마세요.
- 기본 제공 패키지 사용 중지
- Unity 2022 전체 제네릭 공유를 구현합니다. 이렇게 하면 제네릭으로 인한 오버헤드를 줄일 수 있습니다. 그러나 할당을 더 줄이려면 제네릭 사용을 줄이세요.
코드 스트리핑
빌드 크기를 줄이는 것 외에도 코드 스트리핑은 메모리 사용량을 줄입니다. IL2CPP 스크립팅 백엔드를 대상으로 빌드할 때 관리형 바이트코드 스트리핑 (기본적으로 활성화됨)은 관리형 어셈블리에서 사용되지 않는 코드를 삭제합니다. 이 프로세스는 루트 어셈블리를 정의한 다음 정적 코드 분석을 사용하여 이러한 루트 어셈블리가 사용하는 다른 관리형 코드를 결정하는 방식으로 작동합니다. 도달할 수 없는 코드는 삭제됩니다. 관리형 코드 스트리핑에 관한 자세한 내용은 최적화 트렌치에서 얻은 교훈: Unity 2020 LTS로 더 나은 관리형 코드 스트리핑 블로그 게시물 및 관리형 코드 스트리핑 문서를 참고하세요.
네이티브 할당자
네이티브 메모리 할당자를 실험하여 메모리 할당자를 미세 조정합니다. 게임에 메모리가 부족한 경우 할당자가 느리더라도 더 작은 메모리 블록을 사용합니다. 자세한 내용은 동적 힙 할당자 예시를 참고하세요.
네이티브 플러그인 및 SDK 관리
문제가 있는 플러그인 찾기 - 각 플러그인을 삭제하고 게임 메모리 스냅샷을 비교합니다. 여기에는 스크립팅 정의 기호로 많은 코드 기능을 사용 중지하고 인터페이스로 결합도가 높은 클래스를 리팩터링하는 작업이 포함됩니다. 게임이 플레이 불가능해지지 않도록 외부 종속 항목을 사용 중지하는 프로세스를 용이하게 하려면 게임 프로그래밍 패턴으로 코드 수준을 높이세요를 참고하세요.
플러그인 또는 SDK 작성자에게 문의 - 대부분의 플러그인은 오픈소스가 아닙니다.
플러그인 메모리 사용량 재현 - 메모리 할당을 실행하는 간단한 플러그인을 작성할 수 있습니다 (이 Unity 플러그인을 참조로 사용). Unity는 이러한 할당을 추적하지 않으므로 Android 스튜디오를 사용하여 메모리 스냅샷을 검사하거나 동일한 프로젝트에서
MemoryInfo클래스와Runtime.totalMemory()메서드를 호출합니다.
Unity 플러그인은 자바 및 네이티브 메모리를 할당합니다. 방법은 다음과 같습니다.
자바
byte[] largeObject = new byte[1024 * 1024 * megaBytes];
list.add(largeObject);
네이티브
char* buffer = new char[megabytes * 1024 * 1024];
// Random data to fill the buffer
for (int i = 1; i < megabytes * 1024 * 1024; ++i) {
buffer[i] = 'A' + (i % 26); // Fill with letters A-Z
}