【Unity】UnityEvent で 利用した Delegate は初期化しないとリークする - うにてぃブログ
昨日の記事でリークすることが判明しましたが、なぜリークするのか内部処理を追ってみます
※ Unity2020.3.14f1 UnityEditor上 Memory Profilerで確認
UnityEvent
UnityEvent.csのコードにて AddListener を行った処理は以下になります
// Unity C# reference source // Copyright (c) Unity Technologies. For terms of use, see // https://unity3d.com/legal/licenses/Unity_Reference_Only_License [Serializable] public class UnityEvent : UnityEventBase { public void AddListener(UnityAction call) { AddCall(GetDelegate(call)); } } public abstract class UnityEventBase : ISerializationCallbackReceiver { private InvokableCallList m_Calls; internal void AddCall(BaseInvokableCall call) { m_Calls.AddListener(call); } }
同じく UnityEvent.cs 内にある Addlistener を見てみると m_RuntimeCalls に追加されており、クリアされているのは Clear を呼び出したタイミングになります
class InvokableCallList { private readonly List<BaseInvokableCall> m_RuntimeCalls = new List<BaseInvokableCall>(); public void AddListener(BaseInvokableCall call) { m_RuntimeCalls.Add(call); } public void Clear() { m_RuntimeCalls.Clear(); }
これを呼び出しているのは RemoveAllListeners でした
public abstract class UnityEventBase : ISerializationCallbackReceiver { public void RemoveAllListeners() { m_Calls.Clear(); } }
つまり、UnityEvent ではデリゲートが List にキャッシュされ、RemoveAllListener もしくは RemoveListener を呼ばない限りキャッシュから消されなさそうです
これは デリゲートを内部で利用した場合 (onClick.AddListener*1;) に限らず問題がありそうなので、UnityEvent に登録した場合は 開放されるタイミングで RemoveAllListener を呼び出したほうが無難かもしれません