マネージドコードストリッピングは、アプリケーションのバイナリファイルのサイズを小さくするための、ビルドプロセスにおける重要なステップです。これは未使用コードを削除することで実現されます。
コードを削除することで、そのコードがコンパイルされたり最終ビルドに含まれたりしないようにします。これにより、IL2CPP バックエンドを使用しているプロジェクトのメモリ使用量はわずかに減少しますが、マネージコードのストリッピングのレベルを高くすることには、実行時に型やメソッドが見つからなくなる(その他の問題も発生する)リスクが常にあります。
ビルドプロセスで、使用されていないと判断されたコードは、結果的に削られることになります。必要なアセンブリを手動で link.xml ファイルに追加することは、削除されないようにするための最も簡単な方法ではありません。私が Unity ソフトウェア開発コンサルタントとして行っているプロジェクトレビューの中で、マネージドコードストリッピングをどのように扱えばよいかという質問を顧客から受けたことがあります。そこで、マネージドコードストリッピングに関する新しいアノテーション属性を活用してワークフローを改善するためのヒントとベストプラクティスを集めました。
未使用コードを削除することは、IL2CPP スクリプトバックエンドを使う時に特に重要です。Unity リンカーは、Mono IL リンカーを Unity で動作するようにカスタマイズしたもので、マネージドコードを取り除くための静的解析を行います。
Unity では、IL2CPP のマネージドコードストリッピングについて、Low、Medium、High の 3 つのレベルをサポートしています。マネージドコードストリッピングのマニュアルでは、コードストリッピングプロセスの仕組み、特定のコードが削除する要因、ストリッピングレベルの違いなどを説明しています。要するに、コードストリッピングのレベルが高ければ高いほど、リンカーはより積極的に使われていないコードを見つけて削除しようとします。マネージドストリッピングレベルは、プロジェクトの Player Settings で変更できます。
リンカーが使用されていないコードを特定するために活用している静的解析は、実行時にしか定義されていないオブジェクトの型がある場合、すべてのケースをカバーすることはできません。このようなケースでは、「偽陽性」となってしまいます。コンパイル時にはクラスやメソッドへの参照はないかもしれませんが、実行時にはコードの一部でそのクラスやメソッドが必要になります。この文脈では、リフレクションを使用したコードが良い例となります。次のようなスニペットを考えてみましょう。
これは正しく、かつよく使われるタイプのコードですが、リンカーは MyAssembly、MyType、MyMethod が実行時に実際に使用されているかどうかを知りません。このため、これらのコードが削除されることがあり、ひいては実行時エラーが発生する可能性があります。詳しくは、スクリプトの制限のマニュアルをご確認ください。
Zenject のような依存性注入フレームワークや、Newtonsoft.Json のようなシリアライゼーションライブラリを使用している開発者は、「偽陽性」のコードストリッピングが発生する可能性があることを認識し、対処しなければなりません。ここでは、代表的なアプローチをご紹介します。
Addressables パッケージでも、LinkXmlGenerator を利用しています。Addressables のビルドスクリプトは、グループ内のアセットのリストを確認し、アセットが使用する型を link.xml ファイルに追加します。また、実行時にリフレクションによって Addressable が内部で使用する型を追加します。デフォルトのビルドスクリプトである BuildScriptPackedMode.cs には、スクリプタブルレンダーパイプラインのように、ビルドプロセスのステップとして同様のソリューションの実装に関する詳細が記載されています。
Unity は Assets フォルダーまたはそのサブフォルダー内にある複数の link.xml ファイルをサポートしています。ビルドプロセス中に、複数の link.xml ファイルのエントリがマージされ、リンカーはその内容を考慮します。
[Preserve] 属性を使用するには、手動での作業が必要な場合があります。しかし、皆さんがすでに Unity 2020 LTS でプロジェクトを開発している場合、いくつかの新しいマネージドコードストリッピングのためのアノテーション属性を使って、コードストリッピングで削除すべきでないアセンブリ、クラス、メソッドを簡単かつ正確にマークすることができます。ここでは、その一部をご紹介します。
Unity 2020.1 と 2020.2 では、ツールに API の更新が施され、Mono IL リンカーと同等の性能を持たせています。いくつかのシンプルなリフレクションパターンを検出できるようになりました。つまり、Unity 2020 LTS にアップグレードした場合、link.xml ファイルを使用する理由が減るということです。
Unity 2020 LTS によるコーディングワークフローの最適化については、Unity 2020 LTS マニュアルのこの機能の概要とアップデートページ をご覧ください。
テスターやプレイヤーに高品質なビルドを簡単に提供するという 2021 年の目標の一環として、コードストリッピングのワークフローの改善に注力してきました。具体的には、2021.2 のリリースでは、Minimal という新しいマネージドストリッピングレベルを追加しました。これは IL2CPP バックエンドのデフォルトとなります。今後の情報にもご注目ください。