1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

MonoBehaviour.OnDestroyについて

Posted at

有名な話ではあると思いますが時々やらかすことあるので備忘録。

MonoBehaviourは==をオーバーライドしていて、
OnDestroy以降はnullを返す。
OnDestroyが呼ばれてもメモリから消えているわけではない。

まあC#なんだからそりゃそうなんだけれど、
この余計な親切のおかげでメモリリークしやすい。

例えば下記のように二つのMonoBehaviourがあったとして。

public class Sub : MonoBehaviour
{
    void Update()
    {
        if (Input.GetMouseDown(0)) {
            Destroy(this);
        }
    }
}

public class Main : MonoBehaviour
{
    Sub ReferenceToSub;

    void Start()
    {
        ReferenceToSub = gameObject.AddComponent<Sub>;
    }

    void Update()
    {
        if (ReferenceToSub == null) {
            Debug.Log("SubはすでにDestroyされている。");
            return;
        }
    }
}

マウスクリックすることでReferenceToSubはnullを返すようになる。
しかしMainが死ぬまでSubはメモリに残り続ける。

これを防ぐには例えば下記のように明示的にnullを入れてやる。

    void Update()
    {
        if (ReferenceToSub == null) {
            Debug.Log("SubはすでにDestroyされている。");
            ReferenceToSub = null;
            return;
        }
    }

あと、下記のようにインターフェースを使った場合。

public interface ITest
{
    void Test();
}

public class Sub : MonoBehaviour, ITest
{
    void Update()
    {
        if (Input.GetMouseDown(0)) {
            Destroy(this);
        }
    }

    public void Test()
    {
    }
}

public class Main : MonoBehaviour
{
    ITest ReferenceToSub;

    void Start()
    {
        ReferenceToSub = gameObject.AddComponent<Sub>;
    }

    void Update()
    {
        if (ReferenceToSub == null) {
            Debug.Log("SubはすでにOnDestroyされている。");
            return;
        }
    }
}

これはSub.OnDestroyが呼ばれた後も
ReferenceToSubはnullを返さない模様。

なので保持するインターフェースの実態が
MonoBehaviourである可能性があるなら、
そいつがOnDestroyされたことは別の手段で知る必要がある。

インターフェースはGC.Allocを回避しつつ
コールバック処理できるありがたい存在なんだけど、
こういう罠もある。

最後に、これも有名な話ですが
OnDestroyが呼ばれた後、
ReferenceToSub==nullはtrueなのに
ReferenceToSub?はnullを返さない。
これ何とかしてくれんかなあ。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?