AssetBundle에서 모델을 사용할 때 메모리 누수 문제 및 해결

[마지막 갱신일: 2020/10/21]

클리핑을 사용하여 모델의 Prefab을 AssetBundle에서 로드 및 언로드하면 CubismMaskTexture를 처리하는 방법에 따라 메모리 누수가 발생할 수 있습니다.

여기에서는 그 원인과 미대응의 이유 및 그 대책에 대해 설명합니다.

 

개요

클리핑이 설정된 모델을 Unity로 처리하는 경우 CubismMaskController를 사용합니다.
CubismMaskController.MaskTexture 에 세트하는 마스크용 텍스쳐(CubismMaskTexture 의 인스턴스)는, 세트되어 있지 않은 경우, 초기화시에 어플리케이션내의 GlobalMaskTexture 를 참조합니다.
그러나 프로젝트 사양에 따라 CubismMaskTexture의 인스턴스를 애플리케이션 측이 아닌 AssetBundle에 포함시킬 수 있습니다.
이 경우 AssetBundle에서 모델을 로드 및 언로드하면 메모리 누수가 발생할 수 있습니다.

메모리가 누출되는 원인은 CubismMaskTexture 내부의 RenderTexture가 생성된 후에 남아 버리는 것입니다.
대책은 CubismMaskTexture를 사용하는 방법에 따라 두 가지가 있습니다.

case 1: 모든 모델에서 하나의 CubismMaskTexture를 사용하는 경우
1-1. CubismMaskControllerInspector.cs의 EditorGUILayout.ObjectField를 삭제합니다
1-2. CubismMaskController.cs에서 직렬화 된 _maskTexture를 직렬화하지 않는 처리로 변경합니다
1-3. AssetBundle을 다시 만듭니다

case 2: 모델당 CubismMaskTexture를 인스턴스하는 경우
2-1. CubismMasktexture.cs에서 _renderTexture를 제거하는 메서드를 만듭니다
2-2. 모델을 파기할 때 2-1에서 만든 메서드를 호출합니다
2-3. AssetBundle을 다시 만듭니다

위의 조치 중 하나를 수행하면 메모리 누수가 제거됩니다.

 

배경·원인

Live2D 모델에서 클리핑이 설정된 모델을 AssetBundle화한 후 거기에서 모델을 로드 언로드하면 메모리 누수가 발생합니다.

원인은, 모델을 로드할 때마다 마스크용의 RenderTexture가 생성되어, 모델이 삭제되어도 RenderTexture는 남아 버리기 때문입니다.
컴퍼넌트에 설정되어 있는 오브젝트는 오브젝트의 참조가 아닌 오브젝트의 카피로 AssetBundle화됩니다.
결과적으로 AssetBundle화를 통해 모델을 생성하면 CubismMaskController.MaskTexture에 CubismMaskTexture의 인스턴스인 GlobalMaskTexture가 설정되어 있으면 모델을 로드할 때 동시에 GlobalMaskTexture의 복사본도 생성되며 RenderTexture도 만들어집니다.
그러나 모델을 삭제해도 RenderTexture는 삭제되지 않고 남아 버립니다. 그 결과 메모리 누수가 발생합니다.

Cubism SDK에 대한 이 버그의 수정 반영은 다음의 3가지 이유로 이루어지지 않습니다.

  1. 마스크용 RenderTexture의 취급 방법에 따라 대응 방법이 다르기 때문에
  2. 이해하기 쉽고 구조의 단순성에 중점을 둔 CubismComponents가 복잡해지기 때문에
  3. AssetBundle을 사용하지 않으면 문제가 없기 때문에

 

대책

대책에 있어서의 주의점

이 섹션에서는 두 가지 조치를 제시합니다.

주의점으로서, 2개의 대책은 독립한 대책 방법이기 때문에, 동시에 2개의 대책을 1개의 프로젝트로 실시하지 않도록 해 주세요.

대책은 CubismMaskTexture의 사용법에 따라 대책이 다릅니다. 하나의 CubismMaskTexture 만 사용하는 경우와 모델 당 CubismMaskTexture를 인스턴스화하고 사용하는 경우입니다.
여기에서는 2개의 사용 방법에 대해, 각각 1개씩 대책의 설명을 실시합니다.

 

Case 1: 하나의 CubismMaskTexture를 사용하여 모델을 표시하는 경우

하나의 CubismMaskTexture를 사용해 모델을 표시하고 있는 경우는 이쪽의 대책을 실시합니다.

먼저 CubismMaskControllerInspector.cs에 포함된 EditorGUILayout.ObjectField를 삭제합니다.

 

그런 다음 CubismMaskController.cs에서 직렬화된 _maskTexture를 직렬화하지 않는 처리로 변경합니다.

 

이것으로 대책이 생겼습니다.
이 후 AssetBundle을 다시 작성하십시오.

 

case 2: 모델당 CubismMaskTexture를 인스턴스하는 경우

모델마다 CubismMaskTexture를 인스턴스하는 경우의 대책은 이쪽이 됩니다.

먼저 CubismMaskTexture.cs에 _randerTexture를 Destroy하는 public 메서드를 만듭니다.
다음은 코드 예제입니다.

 

앞에서 설명한 메서드를 모델을 파기할 때 호출합니다.
결과 모델과 마찬가지로 RenderTexture를 삭제할 수 있습니다.

위의 조치가 끝나면 AssetBundle을 다시 작성하십시오.

 

© 2010 - 2022 Live2D Inc.