Android版のロイド(Lloyd)へVOICEVOX Coreを組み込み、ChatGPTの回答を読み上げる実験を続けています。
今回、長めの回答を読み上げた直後に、LloydVoxTestそのものが突然終了する現象が発生しました。
最初は「長文だから落ちた」「WebViewが重かった」「入力待機やマウス位置が関係しているのでは」など複数の可能性がありましたが、crashログを追った結果、少なくとも今回の終了についてはAndroidのlowmemorykiller(LMKD)による強制終了だったことを確認できました。
今回の実験で起きたこと
問題が起きたときのログでは、ChatGPT側の回答取得からVOICEVOX読み上げ開始まで、次のように進んでいました。
12:49:38.384 LloydBridge: COMPLETION ... len=797
12:49:38.387 LloydVoicevox: SPEAK_START len=797
797文字の回答を取得し、そのまま音声合成を開始しています。
その数秒後、Android側ではlowmemorykillerが複数のプロセスを次々に終了させ始め、最終的にLloyd自身も対象になりました。
lowmemorykiller: Kill 'com.example.lloydvoxtest'
oom_score_adj 0
rss 1109676kB
swap 1055292kB
reason: min watermark is breached and swap is low
続いて、Lloydのプロセスは signal 9 (Killed) で終了しています。
Javaの例外ではなかった
今回確認したログでは、典型的な FATAL EXCEPTION や OutOfMemoryError は見つかりませんでした。
つまり、アプリ内部でJava/Kotlin例外が発生して自滅したというより、システム全体のメモリ圧迫が深刻になり、Android側からプロセスを強制終了されたと見るのが自然です。
Lloydが終了する直前には、Gboard、Chrome、WebView関連、Google系サービスなど、ほかのプロセスもlowmemorykillerの対象になっていました。
このため、少なくとも今回の実験では「Lloydだけが単独で異常終了した」という状態ではなく、エミュレータ全体がかなり厳しいメモリ不足状態に入っていたと考えています。
RSS約1.1GB、swap約1.05GB
lowmemorykillerがLloydを終了した時点では、ログ上でRSSが約1.1GB、swapが約1.05GBと記録されていました。
ここで注意したいのは、この2つを単純に足して「Lloydが2GB以上の実メモリを使った」と断定することはできない点です。RSSには共有マッピングなども含まれ、swapも別の意味を持ちます。
ただし、メモリ圧迫が極端な状態だったこと自体は明らかです。
分かったのは「直接の終了原因」まで
ここは今回いちばん大事なところです。
LMKDによるメモリ枯渇で終了したことは確認できた。
しかし、何がメモリを増やしたのかはまだ未確定。
現時点では、次のような候補を考えています。
- VOICEVOXの音声合成時に一時的な大きなメモリピークが発生した
- 音声合成やWAVなどのネイティブメモリが解放されず蓄積している
- WebView / Chromium側のメモリ使用量が大きい
- WebView、VOICEVOX、IMEなどが同時に動き、合計で限界を超えた
- 797文字を一括合成したことでピークが大きくなった
どれもまだ仮説です。
マウス・focusの高負荷問題とは分けて考える
同じ日に、Android EmulatorをアクティブにしたときだけPC負荷が上がる別の問題も調べています。
こちらでは、mouse / hover / focus、WebView、IME、artd などの関係を切り分けています。
Android Emulatorがアクティブ時だけ重くなる? ロイド開発で起きた謎の高負荷を追う【調査中】
今の段階では、この高負荷問題と今回のLMKD終了を同じ原因だとは考えていません。 同じ環境で起きているので関係する可能性はありますが、証拠が出るまでは別問題として扱います。
Vulkan問題はすでに別件として解決済み
以前、Android Emulator上のWebViewが真っ黒・真っ白になる問題がありました。
その件は、Vulkanを無効化することでYouTubeとChatGPTの表示が正常化し、描画問題としては解決しています。
Android EmulatorのWebViewが真っ黒・真っ白なのにDevToolsでは正常表示された話|原因はVulkanだった
今回のメモリ枯渇は、その表示問題を解決した後の開発で新しく見つかった別の問題です。
次にやること
次はコードを大きく変更せず、まず「いつメモリが増えるのか」を測ります。
起動直後 ↓ ChatGPT表示後 ↓ 文字入力待機 ↓ SPEAK_START前 ↓ VOICEVOX合成中 ↓ 再生終了後
さらに、100文字程度の短い文章から始めて、通常入力と入力後待機状態を同条件で比較します。
ここで見たいのは、次の違いです。
- 合成中だけ急上昇する → 一時的なピーク型
- 読み上げを繰り返すたびに増えていく → 解放漏れ・蓄積型
- WebViewを表示した時点ですでに大きい → WebView / Chromium側の比率が大きい可能性
原因の境界が見えてから、必要なら長文分割やネイティブリソースの解放、VOICEVOXモデル管理、WebView側の対策を検討します。
今の結論
今回の検証で分かったことは、かなりシンプルです。
Lloydが落ちた直接の理由は、AndroidのLMKDによるメモリ枯渇だった。
次に調べるべきなのは、「誰が、いつ、どれだけメモリを増やしているのか」。
まだ解決編ではありません。
ただ、クラッシュの正体が「なんとなく長文に弱い」から「メモリ圧迫でシステムに殺されている」まで進んだことで、次に見る場所はかなり絞れました。
原因が特定できたら、続編として記録します。



コメントを残す