// Bad
void Func(IInterface value) { }
// Good
void Func<T>(T value) where T : IInterface { }けちゃっぷ @kechako
9年目突入 おめでとうございます🎉
Unity Technologies が開発・販売を行うゲームエンジン
クラスプラットフォームに対応している
iOS、Android、Windows、macOS、Linux、……
スクリプティングは C# を使用できる
仕事で Unity を使ってアプリを開発している

オペレーターがアバターになって客と会話する
Coreパッケージ
Operator App
Customer App
これらを Unity で開発している
Operator App 及び Customer App の共通機能をパッケージとして提供
サーバーとの通信部分(gRPC、UDP)は Go で実装
音声処理は libwebrtc の一部(AudioProcessor、Opus codec、Resampler)をネイティブライブラリ化
その他、共通のアセットなど
iOS アプリ
顔の動きをキャプチャーしてサーバーに送信
音声の送受信
Android アプリ
音声の送受信
顔の動きを受信して音声と同期して表示
カメラ映像をサーバーに送信
Customer App が一定時間経過するとクラッシュする
Unity 内で例外が起こるとかではなく SIGSEGV で
クラッシュログの Backtrace が毎回違う?
Out of Memory
端末のメモリは 2GB(少なくね?)
メモリが半分くらいしか空いてない
アプリの使用メモリーが少しずつ増えている
一定時間経過後 Out of Memory
リークするようなコードは見あたらない
しかし、アロケーションが頻発する雑なコード
Unity の GC が仕事をしていないようだ……
(Unity の GC はメモリの移動は行なわないので、断片化によりヒープサイズが拡大し続けたりする)
アロケーションを削減
消費メモリーを削減
OS の空領域を増やす
音声とかカメラ映像とかのバッファーをプールし再利用する
クラスはヒープに配置される = アロケーションが発生する
構造体はスタックに配置される
ラムダ式の中で外側の変数を使用するとキャプチャーされる
コンパイラーがクラスを生成するのでアロケートされる
値型を object や interface などの参照型に代入すると、参照型に変換(ボックス化)される
ヒープに領域が確保され、スタックから値がコピーされる。
ジェネリクスに制約を付けて回避
// Bad
void Func(IInterface value) { }
// Good
void Func<T>(T value) where T : IInterface { }アバターモデル(VRM)のテクスチャが無駄にでかかった
テクスチャを全体的に半分に
メモリ消費が200MBほど減った
なにやらメモリを240MBほど消費しているサービスが
AirPlay や Chromecast のホストになるアプリがプリインストールされている
不要なアプリは全て削除
かなり安定したが、それでもたまにクラッシュする
Unity IDE 上だとまったく問題無い
Android アプリのバックエンドを IL2CPP から Mono に変更
バックエンドが Mono だと、クラッシュしなくなった。
C# 歴長いからって雑な書き方はあかん
Unity 向けの C# の書き方を
C# はコンパイラーがいろいろやらかすやってくれる
普通に書けないのに C# である意味とは……
IL2CPP で安定しないのはよくわからん
Unity でゲーム開発者してる人達がんばってるなぁ