LoginSignup
2
4

More than 3 years have passed since last update.

Unityにおけるオブジェクト破棄のタイミング

Posted at

概要

シングルトンオブジェクトのデストラクタでゲーム設定の保存処理を行うようにしたところ、エディタ終了時にクラッシュする現象が発生しました。原因を調査すると、Unityエディタではプレイ中に生成されたオブジェクトが少し変わったタイミングで破棄されていました。

結論

Unityエディタでプレイ中に生成されたオブジェクトは次回のプレイ開始時及びエディタの終了時に破棄されます。直感的にはプレイ停止時に破棄されていそうですが、次のプレイ、もしくはエディタの終了時までオブジェクトは保持されているようです。

実験

以下のコードでデストラクタの実行タイミングを確かめます。

SingletonDestractor.cs

using UnityEngine;
public class SingletonDestractor
{
    static SingletonDestractor instance;
    static public SingletonDestractor Instance
    {
        get
        {
            if(instance == null)
            {
                instance = new SingletonDestractor();
            }
            return instance;
        }
    }

    public void Call()
    {
        Debug.Log("Call");
    }

    ~SingletonDestractor()
    {
        Debug.Log("Destract");
    }
}

デストラクタでDebug.Logを呼び出すシングルトンオブジェクトです。
以下のコンポーネントでこれを生成します。

Caller.cs
using UnityEngine;

public class Caller : MonoBehaviour
{
    void Start()
    {
        SingletonDestractor.Instance.Call();   
    }
}

実行、停止したところ、コンソールは以下のようになりました。
image.png

デストラクタ内で呼び出しているはずのDebug.Log("Destract");が実行されていません。
この状態で再度実行、停止したところ、コンソールは以下のようになりました。
image.png
このことから、前のプレイ時のSingletonDestractorオブジェクトが今回のプレイ開始時に破棄されたことが分かります。間が2秒ほど空いていることから、恐らくプレイボタンを押してから実行が開始されるまでの間に破棄されていると思われます。

また、しばらく別の作業をしていた所、以下のようになりました。
image.png
時間経過、もしくは何らかのタイミングでも破棄されるようです。いずれにせよデストラクタの実行タイミングはコントロールしづらく、使用は避けたほうがいいでしょう。

解決策

オブジェクト破棄時に何か処理をしたい場合は、MonoBehaviourを継承して、OnDestroy関数を使うべきです。具体的には以下のようにします。

SingletonDestractor.cs
using UnityEngine;

public class SingletonDestractor : MonoBehaviour
{
    static SingletonDestractor instance;
    static public SingletonDestractor Instance
    {
        get
        {
            if(instance == null)
            {
                var go = new GameObject();
                instance = go.AddComponent<SingletonDestractor>();
                DontDestroyOnLoad(go);
            }
            return instance;
        }
    }

    public void Call()
    {
        Debug.Log("Call");
    }

    void OnDestroy()
    {
        Debug.Log("Destract");
    }
}

このようにすると、先程のシングルトンクラスと同様に扱うことができ、なおかつゲームオブジェクトの破棄はプレイ終了時に行われるので、意図したタイミングでデストラクタ相当の処理を行うことができます。実際にこちらのクラスでプレイ、停止したところ、コンソールは以下のようになりました。
image.png
正しく終了時に破棄が行われていることが確認できます。

2
4
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
2
4