Xamarin.Forms+UrhoでResourceCacheを下手に取り扱うとクラッシュする

Pocket

バグ?と回避方法の紹介です。

  1. アプリがクラッシュする状況
  2. 回避策
  3. 推定原因
  4. まとめ

1. アプリがクラッシュする状況

本記事を読んでいる方と似ているかもしれません。
まずはざっくりとした経緯から。

  • クロスプラットフォームアプリ用にXamarin.Formsを導入
  • 3DCGを表示したくなったのでUrhoSharpを導入
  • UrhoSurface上に色々シーンを作る都合でリファクタリング
  • ページ遷移のテストしたらいきなりクラッシュ

そして私の場合、アプリのページ構成としては最上位にNavigationPageを使い、
その下でContentPageを遷移させるようにしていました。

  • MainPage : NavigationPage
    • StartPage: ここではUrhoSurface不使用
    • AppPage: 画面の一部としてUrhoSurfaceを使用

起動時にStartPageを表示し、StartPageAppPageを行き来できる構成です。

そしてアプリをクラッシュさせる手順と挙動がこちら。

  • アプリを起動→StartPageが表示
  • AppPageに移動→問題なくUrhoSurfaceにシーン表示
  • StartPageに戻る
  • 再度AppPageに移動→アプリがクラッシュ

実機Android(Oreo)で確認しました。
iOSやUWPでどうなるかは分かりません。

とくに困った点は、try-catchをすり抜けることです。
私はXamarinのデバッガの限界がよく分かってないので内部挙動もピンと来ず、
Urho内部のネイティブコード中でSEGVしてる?」と憶測が立った程度でした。

2. 回避策

結論としては、UrhoApplication.ResourceCacheの参照を他クラスで保持しないようにしたら回避できました。

以下はクラッシュするコードの抜粋です。
xamarin/urho-sampleをもとに作っています。

動くコードが欲しい方はGitHubへ。
上記コードに相当するのはChart.csBarFactory.csです。
クラッシュの有無はAndroidでのみ確認しています。

蛇足ですが、今回のトラブルを起こす「リソースキャッシュの参照保持」は
リファクタリングのつもりでやった変更で、裏目に出たのはやや残念です…。

3. 推定原因

回避策が分かったところで原因推定です。
Urhoのソースは読んでないので、単なる当てずっぽうです。
興味ある方は調べてみてください。

  • マネージ: 画面をアンロードする
  • マネージ: ユーザーコードからUrhoSurface.OnDestroy()を実行1
  • ネイティブ: OnDestroyの実行時点でシーン破棄し、リソースキャッシュを削除
  • マネージ: Applicationと関係ない所にResourceCacheの参照がまだあるので、リソースキャッシュの削除に気づかない
  • (いったん別ページに遷移)
  • マネージ: ふたたびUrhoSurfaceを使う画面をロード
  • マネージ: Applicationを立ち上げなおしてResourceCacheを取りに行くが、ここでリソースキャッシュがまだ生きていると思い込んでるので、前回確保したリソースキャッシュを使おうとする
  • ネイティブ: 解放済みのメモリを叩かされてSEGV

4. まとめ

…いやまとめ以前に「issueで上げろよ」って話なんですが。
どうもページ遷移クラッシュの話題はスルーされてそうだし、
個人的には回避策で割と納得しちゃったのでモチベが無いというか…。

他力本願になりますが、やる気ある方は是非どうぞ。


  1. 抜粋したコードには含めていませんが、xamarin/urho-samplesで実装を見るとPageOnDisappearingUrhoSurface.OnDestroy()を呼んでいます。 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください