LoginSignup
7
7
お題は不問!Qiita Engineer Festa 2023で記事投稿!

[Unity] Debug.Logの呼び出しをリリースビルドから除外 & GC低減ラッパークラスを作る

Last updated at Posted at 2023-06-20

1. Debug.Logの問題点

Unityでコンソールに情報を出力する関数としては以下のようなものがある。

Debug.Log();
print();

これらはリリースビルド時に除外される....ということはなく、普通に呼ばれている。
Debug.logger.logEnabled = false でログを無効にすることができるが、メソッド呼び出しコストの発生は避けられない。呼び出し時に条件付きコンパイルで囲えば回避できるが、あまり現実的ではない。

条件付きコンパイルで囲う
#if UNITY_EDITOR
    Debug.Log("test");    //疲れる...
#endif

2. メソッド呼び出しコストの回避

この問題に対しては、Debugクラスのラッパークラスを作成しそこからログを出力することで回避することができる。

public static class MyDebug {
    [Conditional("EDITOR_MODE")]
    public static void Log(string msg) => Debug.Log(msg);
}

Conditional属性

指定した条件付きコンパイル シンボルが定義されていない場合、メソッド呼び出しまたは属性を無視するようコンパイラに指示します。

※メソッド呼び出しを無視するのであって、メソッド本体を除外する訳では無い

あとはLogWarning, LogError, Assert, DrawRay などの呼ぶ予定のあるDebugクラスメソッドをラップしていくだけだ。

どうせラッパークラスを作るなら少し改良してみる。

3. GC低減

Debug.Logで複数のデータを文字列にする場合、文字列結合によるアロケーションが発生。

allocation
int score = 71, clearTime = 61;
Debug.Log($"score : {score} clearTime : {clearTime}");
//"score : 71 clearTime : 61"

そもそも引数の型がobject型なので、intfloatなどの値型はboxingが発生する。これも同様にアロケーションが発生。

allocation
int num = 5;
Debug.Log(num);

そこで今回使用するのがZStringという文字列生成ライブラリ。

ZString

文字列生成におけるメモリアロケーションをゼロにする「ZString」というライブラリを公開しました。
Image

これをラッパークラスから呼び出すようにジェネリックメソッドを定義していく... (一部抜粋)

public static class MyDebug {
    public const string DEBUG_CONDITIONAL_TEXT = "UNITY_EDITOR";

    [Conditional(DEBUG_CONDITIONAL_TEXT)]
    public static void Log(string msg) => UnityEngine.Debug.Log(msg);

    [Conditional(DEBUG_CONDITIONAL_TEXT)]
    public static void Log<T1>(T1 arg1) => UnityEngine.Debug.Log(ZString.Concat(arg1));

    [Conditional(DEBUG_CONDITIONAL_TEXT)]
    public static void Log<T1, T2>(T1 arg1, T2 arg2) => UnityEngine.Debug.Log(ZString.Concat(arg1, arg2));

    [Conditional(DEBUG_CONDITIONAL_TEXT)]
    public static void Log<T1, T2, T3>(T1 arg1, T2 arg2, T3 arg3) => UnityEngine.Debug.Log(ZString.Concat(arg1, arg2, arg3));

    [Conditional(DEBUG_CONDITIONAL_TEXT)]
    public static void Log<T1, T2, T3, T4>(T1 arg1, T2 arg2, T3 arg3, T4 arg4)
        => UnityEngine.Debug.Log(ZString.Concat(arg1, arg2, arg3, arg4));
    //省略
    //ZString.Concatは16引数まで定義されている
}

呼び出すときはデータを引数で渡していけばいい(便利)

int score = 71, clearTime = 61;
MyDebug.Log("score : ", score, " clearTime : ", clearTime);    
//"score : 71 clearTime : 61"

4. Debugラッパークラスのデメリット

コンソールに出力されたログをクリックするとラッパークラスのDebugメソッドの場所に飛ばされる。スタックトレースからジャンプするのは少し面倒。

参考

https://tech.cygames.co.jp/archives/3383/
https://creator.game.cyberagent.co.jp/?p=8645
https://shikaku-sh.hatenablog.com/entry/unity-debug-log-optimization

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