本文へ移動

ホーム / App / 第5部 品質・配信・運用

第5部 品質・配信・運用・第10章

パフォーマンスと安定性

★★★ 必須12トピック・面接 6問

アプリの体験を左右する速さと安定性を、測って改善する方法を押さえる。

ひとことで

本番の数字と遅い端末での再現から始め、プロファイラーで原因を見つけ、1つずつ直して計り、段階リリースで確かめる。

「重い・遅い」と言われたら:本番の数字と再現から始める1. 範囲と再現端末・OS・版・画面古い端末・リリース版で2. 本番の数字起動時間・ANR・クラッシュストアの指標・APM3. プロファイルメインスレッドで何をしているかを記録4. 仮説を立てて直す効きそうな順に1回に1つだけ変える5. 計って比べるMacrobenchmark など同じ端末で前後を比較6. 段階リリース少しずつ配って監視劣化を防ぐ仕組み効果がなければ次の仮説へデバッグ版や新しい端末では速く見える。リリース版・遅い端末で計る
アプリの性能改善の流れ

アプリの「重い・遅い」は、端末や OS によって大きく違います。手元の新しい端末では再現しないことが多いので、本番の数字と、遅い端末での再現から始めます。

段階やること道具の例
1. 範囲と再現どの画面・操作か、端末・OS・アプリの版、いつからか。古い端末とリリース版(release ビルド)で再現する(デバッグ版は遅い)問い合わせ・レビュー、テスト用の古い端末
2. 本番の数字起動時間・フレームの遅れ・ANR・クラッシュ・メモリの警告を、版ごと・端末ごとに見るAndroid vitals、Xcode Organizer・MetricKit、Firebase Performance Monitoring など
3. プロファイルメインスレッドで何をしているか、どの関数に時間がかかるかを記録するInstruments、Android Studio Profiler・Perfetto
4. 仮説を立てて直す効果が大きい順に、1回に1つだけ変える(重い初期化の後回し・裏のスレッドへ・画像の縮小など)各トピックの手段
5. 計って比べる同じ端末・同じ条件で何回も計り、中央値で前後を比べるMacrobenchmark、XCTest の性能テスト
6. 段階リリースで確かめる一部の利用者に配り、本番の数字が良くなったか・別の問題が出ていないかを見てから広げる段階的な公開(Google Play・App Store)、ダッシュボード

報告は「起動時間(コールドスタート)の p90 が 2.8 秒 → 1.6 秒。原因は起動時の分析 SDK の初期化」のように、指標・前後の数字・原因をセットにします。

面接ではこう答える

アプリの性能の問題は、本番の数字と再現から始めます。どの画面・端末・版で遅いかを確かめ、古い端末とリリース版で再現します。次にプロファイラーでメインスレッドが何をしているかを見て、効果の大きい順に1つずつ直します。直したら Macrobenchmark などで同じ条件の前後を比べ、段階リリースで本番の数字が良くなったことを確かめてから全員に配ります。

10.2起動時間と描画

用語★★★ 必須
ひとことで

起動時の処理を減らし、メインスレッドで重い処理をしない。60fps(16ms)を超えるとカクつく。

起動の速さは、アプリの第一印象と継続率に直結します。起動には3種類あり、改善の中心は一番遅いコールドスタートです。

種類状態かかること
コールドプロセスがない状態から起動プロセスの作成・ライブラリの読み込み・初期化・最初の画面の描画。一番遅い
ウォームプロセスは残っているが画面は作り直し画面の作成と描画
ホット裏にあった画面を前に出すだけほぼ描画だけ
コールドスタートの内訳と、2つの計り方プロセス作成Application の初期化最初の画面データの表示タップTTID(最初の1コマ)TTFD(使える)SDK の初期化やメインスレッドでの DB・ファイルの待ちは「Application の初期化」を伸ばすTTFD は reportFullyDrawn() を呼ぶと計れる
コールドスタートの内訳。TTID は最初の1コマ、TTFD は使えるようになるまで

コールドスタートの計測

  • Android:adb shell am start -S -W パッケージ名/.MainActivity(-S で先に止めてから起動)で TotalTime を見られます。これは最初の1コマまで(TTID)で、データが出て使えるようになるまで(TTFD)を計るには reportFullyDrawn() を呼びます。継続して計るなら Macrobenchmark の StartupTimingMetric。Play Console の Android vitals は、コールドスタート 5 秒以上・ウォームスタート 2 秒以上・ホットスタート 1.5 秒以上を「遅すぎる」としています(TTID で計る)。
  • iOS:Xcode の Organizer で、実際の利用者の起動時間の分布を見られます。アプリの中からは MetricKit で集められます。Apple は WWDC 2019 の講演「Optimizing App Launch」で、最初の1コマを 400ms 以内に描くことを目標に挙げています。また、起動に長くかかりすぎると OS にアプリを終了させられます。

計るときは、リリース版・性能の低い実機・何回か計った中央値で比べます。デバッグ版やシミュレーターの数字は当てになりません。

面接ではこう答える

起動にはプロセスがない状態からのコールド、プロセスは残っているウォーム、裏の画面を前に出すだけのホットがあり、改善の中心は一番遅いコールドスタートです。最初の1コマまでの TTID と、データが出て使えるようになるまでの TTFD を分けて計り、リリース版を性能の低い実機で何回か計った中央値で比べます。原因の多くは、起動時の SDK の初期化と、メインスレッドでの DB やファイルの待ちです。

ひとことで

推測で直さず、Instruments や Android Studio Profiler・Perfetto でメインスレッドが何をしているかを見て直す。

遅いと分かったら、推測で直さず、プロファイラーで何に時間がかかっているかを見ます。

何に時間がかかっているかは、プロファイラーで見ます。iOS は Instruments の App Launch や Time Profiler、Android は Android Studio の Profiler(CPU の記録)や Perfetto でトレースを取ります。よく見つかる原因は次のとおりです。

原因対策
起動時に全部の SDK(広告・分析など)を初期化している最初の画面に要らないものは後回し・必要になったとき(遅延初期化)
メインスレッドで DB・ファイル・通信を待っている裏のスレッドへ。最初はキャッシュを表示する
最初の画面が重い初めに要る部分だけ描き、残りは後から
Android でコードの初回実行が遅いBaseline Profile を入れて、よく通るコードを事前にコンパイルさせる
道具何が分かるか
Instruments(Time Profiler・App Launch・Hangs)どの関数に時間がかかったか、起動の段階ごとの時間、メインスレッドの止まり
Android Studio Profiler・Perfettoスレッドごとの動き、メインスレッドで何をしていたか、フレームの時間
Macrobenchmark起動時間やスクロールを自動で何回も計り、改善を数字で比べる

面接ではこう答える

性能の問題は、推測で直さず、プロファイラーで何に時間がかかっているかを確かめてから直します。iOS は Instruments の Time Profiler や App Launch、Android は Android Studio の Profiler や Perfetto でトレースを取り、メインスレッドで何をしていたかを見ます。よくある原因は、起動時の SDK の初期化、メインスレッドでの DB やファイルの待ち、最初の画面の重さで、Android では Baseline Profile も効きます。直した後は同じ条件で計り直して比べます。

ひとことで

1コマの描画を 60Hz なら 16.7ms、120Hz なら 8.3ms に収められないとコマが落ちてカクつく。

スクロールやアニメーションのカクつきは、1コマの描画が時間内に終わらないことで起きます。

描画は、60Hz の画面なら 1 コマ 16.7ms、120Hz なら 8.3ms に収まらないとカクつきます。一覧のスクロールのもたつきも、同じプロファイラーでメインスレッドの重い処理を探します。

よくある原因対策
一覧の各行で画像を元の大きさのまま読む・縮める表示の大きさで取り、裏のスレッドで縮める
スクロール中にメインスレッドで解析・DB裏に移す。結果だけをメインで反映する
行の部品が作り直される安定した ID・key を付ける。部品を軽くする
影・角丸・透明の重ね描き重ねる数を減らす。影の形を指定する

Android は Play Console の Android vitals で遅いフレームの割合を、iOS は Xcode Organizer でスクロールのもたつき(Hitch rate)を、実際の利用者のデータで見られます。

1コマの予算を超えると、カクつく予算(60Hz なら 16.7ms)予算を超えたコマ(赤)は表示が間に合わず、前のコマが出たままになる
60Hz なら 16.7ms、120Hz なら 8.3ms の中に描画を収めないとコマが落ちる

面接ではこう答える

画面は 60Hz なら1秒に60回、120Hz なら120回描き直されるので、1コマの描画はそれぞれ 16.7ms と 8.3ms に収める必要があります。収まらないと前のコマが出たままになり、カクつきとして見えます。原因の多くは、スクロール中にメインスレッドで画像を縮めたり、解析や DB を読んだりすることなので、それらを裏に移し、一覧の行に安定した ID を付けて作り直しを減らします。

ひとことで

メモリリークは強制終了の原因になる。バックグラウンド処理と位置情報は電池を減らす。

スマホはメモリが少なく、使いすぎると OS にアプリを終了されます(iOS では Jetsam、Android では Low Memory Killer)。電池も、使いすぎると利用者に消されたり、OS に裏の動きを止められたりします。

循環参照

Swift は参照の数を数えてメモリを解放します(ARC)。2つのものがお互いを強く持ち合うと数が 0 にならず、ずっと解放されません。これが循環参照です。よくあるのは、ViewModel が持つクロージャーの中で self を強く持つ形です。

api.onUpdate = { [weak self] value in
  self?.items = value     // weak にしないと self とクロージャーが持ち合う
}
循環参照:どちらも解放されない[weak self]:画面を閉じれば解放ViewModelクロージャー強く持つ強く持つViewModelクロージャー強く持つweakAndroid では、寿命の長いもの(シングルトン)が Activity を持ち続けると同じように漏れる
お互いを強く持つと解放されない。片方を weak にすると解放される

デリゲートは weak var delegate にします。見つけるには Xcode の Memory Graph Debugger や Instruments の Leaks を使います。Android(Kotlin)はガベージコレクションなので持ち合いは解放されますが、寿命の長いもの(シングルトンや static)が Activity や Context を持ち続けると漏れます。LeakCanary を入れると、デバッグ中に漏れを知らせてくれます。

面接ではこう答える

スマホはメモリが少なく、使いすぎると OS にアプリを終了されます。Swift は参照の数を数えて解放する ARC なので、2つのものがお互いを強く持ち合う循環参照があると解放されず、クロージャーの中では weak self を、デリゲートは weak を使います。Kotlin はガベージコレクションですが、シングルトンのような寿命の長いものが Activity や Context を持ち続けると漏れます。iOS は Memory Graph Debugger、Android は LeakCanary で見つけます。

ひとことで

裏の処理は OS がまとめて後回しにする。確実にやりたいことは WorkManager や BGTaskScheduler に頼み、通信はまとめて送る。

電池を減らすアプリは、利用者に消されるだけでなく、OS にも裏の動きを止められます。iOS も Android も、裏の処理に強い制限をかけています。

置いたままの端末では、裏の処理はまとめて後回し窓窓窓窓Doze:画面が消えて置いたままだと、通信・ジョブ・アラームが「窓」まで待たされる窓の間隔はだんだん長くなる確実に実行したい処理は WorkManager に条件付きで頼み、急ぐ通知は優先度の高いプッシュで
使われない時間が長いほど、また使われないアプリほど、裏の処理はまとめて後回しにされる
OS主な制限と使う仕組み
iOS裏に回ると数秒で止まる。定期処理は BGTaskScheduler、転送はバックグラウンドの URLSession。実行のタイミングは OS が決める
AndroidDoze(端末を置いたままにすると通信や処理をまとめて後回し)、App Standby Buckets(あまり使わないアプリほど制限が強い)、裏からのサービス起動の制限。確実にやりたい処理は WorkManager、利用者に見える処理はフォアグラウンドサービス(Android 14 以降は種類の宣言が必要)

電池を減らすコツは、通信をまとめて送る、位置情報は必要な精度と頻度だけにする、裏でのポーリングをやめてプッシュにする、ことです。Android Studio の Energy の表示や Xcode の Energy の項目で確かめます。

Android の WorkManager では、最小の間隔が15分の定期の処理や、「Wi-Fi のとき」「充電中」などの条件を付けた処理を頼めます。実行の時刻は OS が決めるので、ずれる前提で使います。

面接ではこう答える

スマホの OS は電池を守るため、裏の処理を強く制限します。Android では端末を置いたままにすると Doze で通信やジョブがまとめて後回しにされ、あまり使わないアプリほど App Standby Buckets で制限が強くなります。確実にやりたい処理は WorkManager に条件付きで頼み、利用者に見える処理はフォアグラウンドサービスにします。iOS は BGTaskScheduler とバックグラウンドの URLSession を使い、どちらでも通信はまとめて送り、ポーリングをやめてプッシュにします。

ひとことで

画像は縦×横×4バイトに広げられてメモリを使う。表示の大きさに縮めて、裏のスレッドで読む。

アプリのメモリ不足の原因で一番多いのが画像です。画像は表示のときに縦 × 横 × 4バイト(色の情報)に広げられるので、ファイルが小さくても、ピクセル数が多いとメモリを大きく使います。

やること理由
表示する大きさで取る・縮めて読む4000×3000 の写真は広げると約 48MB。表示が 600×450 なら約 1MB で済む
サーバーに大きさを指定して取る画像の変換の仕組み(CDN の機能など)で、端末に合った大きさを返してもらう
縮める処理は裏のスレッドでメインスレッドで縮めるとスクロールがカクつく
キャッシュには上限をメモリのキャッシュはアプリのメモリの一部までにし、メモリ不足の通知で捨てる
画面から消えたら取り消す速くスクロールしたときに、見えなくなった行の読み込みを止める

Android の Coil・Glide、iOS の Kingfisher・SDWebImage などのライブラリは、これらをまとめてやってくれます。iOS で自前で縮めるなら、ImageIO の縮小画像の作成(CGImageSourceCreateThumbnailAtIndex)を使うと、元の大きさに広げずに縮められます。

画像のメモリ = 縦 × 横 × 4バイト4000 × 3000 のまま読む約 48MB(1枚で)表示の大きさ 600 × 450 に縮める約 1MBファイルの大きさ(JPEG で数 MB)ではなく、表示のために広げた後の大きさでメモリを使う一覧に何十枚も並ぶと、縮めないだけでメモリ不足の終了につながる
表示する大きさに縮めて読めば、同じ見た目でメモリは数十分の一になる

面接ではこう答える

画像は表示のときにピクセルごとに広げられるので、メモリは縦かける横かける4バイトほど使います。4000 かける 3000 の写真なら約 48MB で、一覧に何枚も並ぶとメモリ不足で終了されます。対策は、サーバーに表示の大きさで返してもらうか、端末で表示の大きさに縮めて読むことで、縮める処理は裏のスレッドで行い、キャッシュには上限を付けます。普段は Coil や Kingfisher などのライブラリの設定を確かめるのが確実です。

アプリのサイズが大きいと、ダウンロードをやめる人が増え、端末の容量が少ない人には入れてもらえません。ストアで見えるダウンロードの大きさと、入れた後の大きさの両方を見ます。

やることiOSAndroid
端末に必要な部分だけ配るApp Thinning(端末ごとに必要な画像・コードだけ)AAB で、画面の密度・CPU・言語ごとに分けて配る
使っていないコードを消す使っていないライブラリの見直しR8 の縮小、isShrinkResources で使っていない画像も消す
画像を軽くするAsset Catalog で管理し、ベクターや適切な形式を使うベクター画像・WebP
後から取りにいくOn-Demand Resources・Background AssetsPlay Feature Delivery・Play Asset Delivery
大きさを確かめるApp Store Connect のサイズの報告Play Console のアプリサイズ、Android Studio の APK Analyzer

大きくなる原因の多くは、ライブラリ(特に広告・分析の SDK)と画像・動画・フォントです。プルリクエストごとにサイズを記録して、急に増えたら気づけるようにしておくと、後から削るより楽です。

ひとことで

クラッシュしないユーザーの割合(クラッシュフリー率)を指標にし、ANR(応答なし)も監視する。

アプリは一度落ちると、利用者の評価やストアの順位にすぐ響きます。サーバーと違って手元でログを見られないので、落ちた情報を集める仕組みが必須です。

Crashlytics など

Firebase Crashlytics や Sentry などの SDK を入れると、落ちたときのスタックトレース(どの関数で落ちたか)・機種・OS の版・アプリの版が集まります。ストアの管理画面(App Store Connect・Xcode Organizer、Play Console)でも見られます。

落ちた情報は次の起動で送られ、名前に戻して集計されるアプリが落ちるSDK が記録端末に保存次の起動で送る名前に戻すdSYM・mapping集計版・機種ごとdSYM・mapping を毎回アップロードしないと、関数名が読めないまま集まる新しい版でクラッシュしなかった利用者の割合が下がったら、段階的リリースを止める
クラッシュの情報は次の起動で送られ、dSYM・mapping で関数名に戻されて集計される
やっておくこと理由
iOS の dSYM、Android の R8 の mapping ファイルを毎回アップロードするないと関数名が読めない(難読化・最適化された名前のまま)
落ちていない例外も記録する(非致命的なエラー)通信の解析失敗など、落ちないが壊れている箇所が分かる
直前の操作をパンくずとして残す再現の手がかりになる。個人情報は入れない
版ごとのクラッシュしなかった利用者の割合を見る新しい版で悪くなったら段階的リリースを止める判断に使う

目安として、クラッシュしなかった利用者の割合(クラッシュフリーユーザー率)は 99.9% 前後を目標にするチームが多いです。

面接ではこう答える

アプリはサーバーと違って手元でログを見られないので、Crashlytics や Sentry などでクラッシュの情報を集めます。落ちたときのスタックトレースと機種・OS・アプリの版が次の起動で送られ、iOS の dSYM や Android の mapping ファイルで関数名に戻されます。落ちていないエラーや直前の操作も記録し、版ごとのクラッシュフリーユーザー率を見て、新しい版で悪くなったら段階的リリースを止めます。

10.10ANR とハング

用語★★★ 必須
ひとことで

ANR はメインスレッドが長く止まって入力に応えられない状態。DB・通信・ロック待ちを裏に移して防ぐ。

落ちてはいないが画面が固まって動かない状態も、利用者にとってはクラッシュと同じくらい悪い体験です。

メインスレッドが止まると、入力に応えられないメインスレッドで DB・通信・ロック待ちタップ約5秒 → ANRiOS では同じ止まりが「ハング」として記録され、長いと OS にアプリを終了される
入力に5秒ほど応答しないと、Android は「応答していません」を出す

ANR(Application Not Responding)は Android の「アプリが応答していません」のことで、メインスレッドが長く止まると起きます。タップなどの入力に 5 秒ほど応答しないのが代表的な条件です。原因は、メインスレッドでの DB・ファイル・通信、ロックの待ち、重い計算です。iOS でも同じようにメインスレッドが止まると「ハング」として記録され、起動などで長く止まると OS にアプリを終了させられます。

調べ方内容
Play Console の ANR の報告止まったときのメインスレッドのスタックが見られる。どこで待っていたかが分かる
StrictMode(Android)開発中に、メインスレッドでのディスク・通信を見つけて知らせる
Xcode Organizer の Hangs・InstrumentsiOS のメインスレッドの止まりと、その場所

面接ではこう答える

ANR は Android の「アプリが応答していません」で、メインスレッドが長く止まり、タップなどの入力に5秒ほど応答しないと起きます。原因はメインスレッドでの DB やファイルの読み書き、通信、ロックの待ち、重い計算です。Play Console の ANR の報告で止まったときのスタックを見て、どこで待っていたかを特定し、その処理を裏のスレッドに移します。iOS でも同じ止まりはハングとして記録され、長いと OS に終了されます。

Google Play は、実際の利用者の端末から集めた品質の数字を Android vitals として見せ、悪いアプリはストアで不利になるようにしています。

Google Play は Android vitals で、利用者が気づいたクラッシュ率と ANR 率に基準を設けています(全端末の平均でクラッシュ率 1.09%・ANR 率 0.47%、機種ごとではどちらも 8%。直近 28 日の平均で判定)。基準を超えると、ストアで見つけてもらいにくくなったり、ストアのページに警告が出たりします。App Store にはこうした公開の基準はありませんが、落ちるアプリは低い評価やレビューにつながります。新しい版を出したら、最初の数日はこれらの数字を毎日見ます。

主な指標見るところ
利用者が気づいたクラッシュ率全体と機種ごと。基準を超えた機種だけでも影響がある
利用者が気づいた ANR 率同上
起動時間・遅いフレーム改善の目安
電池(過度な wake lock など)裏の処理の作りの見直し

アプリは一度配ると古い版が長く残るので、遅くなる変更を出す前に気づく仕組みが大事です。

何を守るかやり方ポイント
起動時間・スクロールMacrobenchmark・XCTest の性能テストを CI(実機かエミュレーター)で定期的に流すばらつくので回数を重ねて中央値。しきい値は余裕を持たせる
アプリのサイズビルドのたびにサイズを記録し、増えたら PR に表示画像・ライブラリの追加で急に増える
本番の指標版ごとの起動時間・ANR・クラッシュ率のアラートストアの基準を下回ると、ストアでの表示に影響することがある
リリースの出し方段階的な公開と、悪ければ止める基準を先に決めるサーバー側の Feature Flag で機能だけ止められるようにしておく

SDK(広告・分析など)を足すときは、起動時間とサイズへの影響を計ってから入れる決まりにしておくと、少しずつ重くなるのを防げます。

この章のまとめ

🖨 まとめシート(印刷・PDF)
  • 起動時間・スクロールの滑らかさ・メモリ・電池
  • クラッシュ率と ANR を下げる
  • 性能の問題への対応の流れ:本番の数字と遅い端末での再現から始め、プロファイラーで原因を見つけ、1つずつ直して計り、段階リリースで確かめる。
  • 起動時間と描画:起動時の処理を減らし、メインスレッドで重い処理をしない。60fps(16ms)を超えるとカクつく。
  • プロファイラーで原因を探す:推測で直さず、Instruments や Android Studio Profiler・Perfetto でメインスレッドが何をしているかを見て直す。
  • 描画のコマ落ち(ジャンク):1コマの描画を 60Hz なら 16.7ms、120Hz なら 8.3ms に収められないとコマが落ちてカクつく。
  • メモリとメモリリーク:メモリリークは強制終了の原因になる。バックグラウンド処理と位置情報は電池を減らす。
  • 電池と裏の処理の制限:裏の処理は OS がまとめて後回しにする。確実にやりたいことは WorkManager や BGTaskScheduler に頼み、通信はまとめて送る。
  • 画像の読み込みとメモリ:画像は縦×横×4バイトに広げられてメモリを使う。表示の大きさに縮めて、裏のスレッドで読む。
  • クラッシュの収集とクラッシュフリー率:クラッシュしないユーザーの割合(クラッシュフリー率)を指標にし、ANR(応答なし)も監視する。
  • ANR とハング:ANR はメインスレッドが長く止まって入力に応えられない状態。DB・通信・ロック待ちを裏に移して防ぐ。

この章のクイズ

面接ではこう聞かれる

まず答えを見ずに声に出して答え、そのあと開いて比べる。

Q1アプリの起動が遅いと言われたらどう改善しますか?

模範回答

まず計測です。リリース版を性能の低い実機で動かし、コールドスタートの時間を何回か計って中央値を出します。Android なら am start -W や Macrobenchmark、iOS なら Organizer や MetricKit で実際の利用者の分布も見て、どの端末・どの版で遅いのかを確かめます。

次にプロファイラーで原因を探します。Instruments の App Launch や Android Studio の Profiler でトレースを取ると、起動時に全部の SDK を初期化している、メインスレッドで DB やファイルを待っている、最初の画面が重い、といった原因が見えてきます。対策は、最初の画面に要らない初期化を後回しにする、待つ処理を裏のスレッドに移してキャッシュを先に表示する、Android なら Baseline Profile を入れる、などです。直したら同じ条件で再計測して効果を数字で確かめ、CI やリリース後の指標で悪くならないよう見張ります。

深掘りされたら

  • 起動時間をリリースのたびに悪化させないためには?
  • 遅延初期化で気をつけることは?

見られているポイント計測→原因→改善→再計測

Q2メモリリークをどう見つけて直しますか?

模範回答

iOS では Xcode の Memory Graph Debugger や Instruments の Leaks で、画面を閉じたのに残っているオブジェクトを探します。多い原因は循環参照で、クロージャーの中で self を強く持っている、デリゲートを weak にしていない、などです。[weak self] や weak var で片方を弱い参照にして直します。

Android では LeakCanary を入れておくと、デバッグ中に漏れを知らせてくれます。多い原因は、シングルトンや static な変数が Activity や Context を持ち続けることです。Application の Context を使う、寿命の短いものを長く持たない、で直します。画面を何度も開閉して、メモリが戻るかを確かめます。

深掘りされたら

  • weak と unowned の違いは?
  • メモリが足りないと OS はどうしますか?

見られているポイント道具と典型的な原因・直し方

Q3ANR とは何ですか? 原因と対策は?

模範回答

ANR は Android の「アプリが応答していません」で、メインスレッドが長く止まると起きます。代表的なのは、タップなどの入力に 5 秒ほど応答しない場合です。Google Play では ANR 率が基準を超えると、ストアで見つけてもらいにくくなります。

原因は、メインスレッドでの DB・ファイル・通信、ロックの待ち、重い計算、起動時の重い初期化です。対策は、待つ処理をコルーチンで Dispatchers.IO に移す、重い計算は Default に移す、起動時の初期化を後回しにする、です。開発中は StrictMode でメインスレッドのディスクや通信の利用を見つけ、出した後は Play Console の ANR の記録でどこで止まっていたかを見ます。

深掘りされたら

  • iOS で同じような問題はありますか?
  • ANR の記録からどう原因を読みますか?

見られているポイントメインスレッドを止めない考え方と、調べ方

Q4クラッシュ率をどう下げていきますか?

模範回答

まず数字を正しく取ります。Crashlytics などを入れ、dSYM や R8 の mapping を毎回アップロードして、関数名が読める状態にします。そのうえで、影響を受けている利用者が多い順に並べ、上から直していきます。数件の大きな原因で全体の大半を占めていることが多いからです。

新しい版では、段階的リリースの間に版ごとのクラッシュフリー率を見て、悪くなったら止めます。直したら、同じ種類の不具合を防ぐテストや静的解析のルールを足します。落ちていないが壊れている箇所を知るため、非致命的なエラーも記録します。

深掘りされたら

  • クラッシュフリー率はどのくらいを目標にしますか?
  • 再現できないクラッシュはどう調べますか?

見られているポイント影響の大きい順に直し、再発を防ぐ流れ

Q5一覧のスクロールがカクつくとき、何を調べますか?

模範回答

まず、どの端末でどのくらいカクつくかを、リリース版の性能の低い実機で確かめます。60Hz の画面なら1コマ 16.7ms に収まらないとカクつくので、Instruments や Android Studio の Profiler、Perfetto でトレースを取り、メインスレッドで長くかかっている処理を探します。

多い原因は、画像を元の大きさのまま読み込んで縮めている、各行で日付の整形などの重い処理をしている、行の作り直しが多い、です。画像は表示する大きさで読み、整形は前もって済ませ、一覧には安定した ID や key を付けて使い回されるようにします。

深掘りされたら

  • 画像の読み込みで気をつけることは?
  • 120Hz の画面では何が変わりますか?

見られているポイント計測してから原因を絞る進め方

Q6「アプリが重い」というレビューが増えました。どう進めますか?

模範回答

まず本番の数字で範囲を確かめます。Android vitals や Xcode Organizer、APM で、起動時間・フレームの遅れ・ANR を版ごと・端末ごとに見て、いつから・どの端末で悪いかを絞ります。レビューの内容から画面や操作も特定します。

次に、その条件に近い古い端末とリリース版で再現し、プロファイラーでメインスレッドが何をしているかを記録します。例えば起動時に SDK の初期化が重ければ後回しにし、一覧の画像が大きければ縮小して読み込みます。1つずつ直して Macrobenchmark で前後を比べ、段階リリースで本番の数字が良くなったことを確かめてから全員に配ります。最後に CI の性能テストやアラートで、同じ劣化が起きないようにします。

深掘りされたら

  • デバッグ版で計ってはいけないのはなぜですか?
  • 改善の効果をチームや PdM にどう伝えますか?

見られているポイント本番の数字と再現から入るか。プロファイラーで原因を特定し、1つずつ直して計測で確かめ、段階リリースと CI で劣化を防げるか。