使用AssetBundle中的模型时的内存记忆泄漏及其解决方法
最終更新: 2020年10月21日
在从AssetBundle读取和卸载使用剪贴的模型的Prefab时,可能会发生内存记忆泄漏,具体取决于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仍然存在。
在组件上设置的物体是通过物体复制进行AssetBundled化,而不是对该物体的参考。
因此,如果您通过AssetBundle化生成模型,在将CubismMaskTexture的副本GlobalMaskTexture设置到CubismMaskController.MaskTexture时,会在读取模型的同时生成GlobalMaskTexture的复制并创建RenderTexture。
但是,即使删除了模型,RenderTexture仍然没有被删除。结果导致内存记忆泄漏。
由于以下三个原因,此错误的更正没有应用在Cubism SDK中。
- 因为根据如何处理蒙版用RenderTexture,对应方法也有所差异
- 因为专注于结构清晰和简单的CubismComponents变得复杂
- 因为不使用AssetBundle时没有问题
对策
对策的注意事项
本节介绍了两种对策。
请注意,这两个对策是独立的对策,所以不要在一个项目中同时采取两个对策。
对策因您使用CubismMaskTexture的方式而异。只使用一个CubismMaskTexture时,或者为各模型使用一个 CubismMaskTexture副本。
这里将针对两种使用方法,各说明一种对策。
Case 1: 使用一个CubismMaskTexture显示模型时
如果您重复使用一个CubismMaskTexture显示模型,请采取此对策。
首先,删除CubismMaskControllerInspector.cs中包含的EditorGUILayout.ObjectField。
・・・ // Draw mask texture. EditorGUI.BeginChangeCheck(); // 相关部分。删除这一行。 controller.MaskTexture = EditorGUILayout.ObjectField("Mask Texture", controller.MaskTexture, typeof(CubismMaskTexture), true) as CubismMaskTexture; // Apply changes. if (EditorGUI.EndChangeCheck()) { EditorUtility.SetDirty(controller); } ・・・
接下来,将CubismMaskController.cs中序列化的_maskTexture变更为非序列化处理。
・・・ public sealed class CubismMaskController : MonoBehaviour, ICubismMaskTextureCommandSource { /// <summary> /// <see cref="MaskTexture"/> backing field. /// </summary> [SerializeField, HideInInspector] // 相关部分。删除这一行。 private CubismMaskTexture _maskTexture; /// <summary> /// Mask texture. /// </summary> public CubismMaskTexture MaskTexture { ・・・
至此即完成了对策。
然后,请重新创建AssetBundle。
case 2: 如果各模型都有一个CubismMaskTexture副本
如果各模型都有一个CubismMaskTexture副本,请执行以下对策。
首先,在CubismMaskTexture.cs中创建一个对_randerTexture进行Destroy的public方法。
以下为代码示例。
public void DeleteRenderTexture() { DestroyImmediate(_renderTexture); }
在放弃模型的时候调用上述方法。
这样您就可以向模型一样删除RenderTexture。
完成上述对策后,请重新创建AssetBundle。