Unreal Engine Dedicated Server における Asset Stripping の極意(ステップ・バイ・ステップ)
新しくコンパイルした Unreal Engine dedicated server を起動し、軽量な headless プロセスを期待していたとします。しかし、memory profile を取ってみると、そこには数千もの UMaterial、UTexture、USoundWave オブジェクトが RAM を占拠しています。
公式ドキュメントでは、headless サーバーはビジュアルをレンダリングしないとされています。では、なぜサーバーは数メガバイトものテクスチャデータを抱え込んでいるのでしょうか?
インディー開発者なら誰しも、サーバーのホスティングコストが開発資金を圧迫し始める瞬間を知っています。memory bloat のせいで、1台のベアメタルサーバーで50インスタンス動かせるはずが10インスタンスしか動かせない場合、バックエンドのアーキテクチャに問題があります。
このディープダイブでは、unreal engine dedicated server asset stripping の仕組み、なぜ「ゴーストアセット」がメモリに残るのか、そして C++ と Blueprints をどのように設計してそれらを完全に排除するかを解説します。
Dedicated Server における「ゴーストアセット」の正体
問題を解決するには、まず Unreal Automation Tool (UAT) が Server ターゲット向けに cook する際に何を行っているかを理解する必要があります。
Unreal Engine はアセットを2つの部分に分けて管理します:
- UObject Wrapper: メタデータ、プロパティ、リフレクションデータ。
- Bulk Data: 実際の重いデータ(テクスチャの DXT 圧縮ピクセルデータ、メッシュの vertex buffers、オーディオの PCM データ)。
cook 時、クッカーは Bulk Data のストリップには成功します。レンダリングデータは消えます。しかし、UObject wrapper は残ります。
もし Blueprint Class Default Object (CDO) が UTexture2D への hard reference を持っている場合、サーバーはリフレクションシステムを満たし、ヌルポインタによるクラッシュを防ぐために UTexture2D オブジェクトをインスタンス化しなければなりません。Bulk Data が削除され、テクスチャが 10MB ではなく 1KB しか消費しなくても、5万個の UObject をインスタンス化するオーバーヘッドは、甚大な memory bloat と Garbage Collection の負荷につながります。
オーディオやパーティクルも同様ですか?
はい。USoundCue や UNiagaraSystem を hard-reference している場合、サーバーは UObject をロードします。重い PCM データは削除されますが、オブジェクトは存在し続けます。特にパーティクルシステムの場合、CPU で実行されるロジックが含まれていると、サーバーがそのロジックを tick してしまい、CPU リソースを無駄に消費する危険があります。
ステップ 1: サーバーの Memory Bloat をプロファイリングする
計測できないものは最適化できません。以下の引数でサーバーを起動してください:
-LLM -LLMCSV -memoryprofiler
サーバーコンソールで memreport -full を実行します。生成されたレポート内の Obj List を確認すると、どのクラスがメモリを消費しているか一目瞭然です。
ステップ 2: Soft Pointers でハード参照を断ち切る
ゴーストアセットの最大の原因は hard references です。C++ では TSoftObjectPtr を使用してください。Soft references はアセットのパスのみを保持し、明示的に LoadSynchronous() を呼び出さない限り(通常はクライアント側のみ)、UObject はメモリにロードされません。
推奨:Soft Reference (サーバーをクリーンに保つ)
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI")
TSoftObjectPtr<UTexture2D> HeroPortraitSoft;
ステップ 3: NeedsLoadForServer の活用
NeedsLoadForServer 関数をオーバーライドして false を返すことで、特定のビジュアルコンポーネントをサーバー側で完全に無視させることができます。
ステップ 4: 設定によるオーディオとパーティクルのストリップ
DefaultEngine.ini の +DirectoriesToNeverCook を使用して、特定のフォルダを cook 対象から除外できます。また、サーバーの *.Target.cs で bDisableAudio = true; を設定することで、オーディオエンジン自体を無効化できます。
Dedicated Server メモリ最適化のベストプラクティス
- コリジョン用メッシュとビジュアル用メッシュの分離: サーバーには簡略化された
UStaticMeshのみを使用します。 - Construction Scripts の精査:
Switch Has Authorityを使い、サーバーがビジュアルの生成処理をスキップするようにします。 - Data Assets の分離: ステータスデータとビジュアルデータを別の DataAsset に分けます。
- CI/CD でのメモリプロファイリング自動化: ビルドごとにメモリ使用量をチェックします。
最適化されたバックエンドのスケール
サーバーのメモリ使用量を 800MB から 180MB に削減できれば、技術的な大勝利です。AWS や Google Cloud のコストを大幅に抑えつつ、4〜5倍のインスタンスを収容できます。
しかし、これらのサーバーをオーケストレーションするのは容易ではありません。horizOn なら、最適化された Linux ビルドをアップロードするだけで、グローバルなフリート管理とオートスケーリングを自動で行います。
最後に
Unreal Engine の Asset Stripping は強力ですが、アーキテクチャに依存します。Soft pointers への移行とデータの分離を徹底することで、マルチプレイヤーゲームに求められる高いパフォーマンスを実現できます。
バックエンドをスケールさせる準備はできましたか? horizOn を無料でお試しいただくか、API ドキュメントをご覧ください。