モバイルアプリケーションのJank — 概要、原因、解決方法

著者: IT Sectr 公開日: 2026-04-01 読了時間: 10 分

Jankとは、個々のフレームがスキップされることによってインターフェースアニメーションに目に見える途切れや“ひっかかり”が生じることを指す用語です。モバイルアプリでは、フレームのレンダリング時間がディスプレイのリフレッシュレートによって割り当てられた予算を超えるとJankが発生します。Android Developers, 2025によると、Jankは“遅さ”という主観的な感覚の主な原因です — アプリは機能的に完璧でも、FPSが不安定なためにユーザーは遅いと感じます。

重要なポイント

  • Jank — スキップされたフレームで、アニメーションの途切れとして現れます。
  • 主な原因は、フレームごとの時間予算(60 FPSで16.6 ms)を超過することです。
  • Jankは、重いLayout、長いGC、メインスレッドのブロッキング、またはオーバードローによって発生します。
  • 診断にはFrameTimeline(Android)とInstruments(iOS)が使用されます。
  • Jankを解消すると、NPSとユーザー維持率が15~25%向上します。

Jankとは

Jankはコンピュータグラフィックスの用語で、アニメーションがスムーズに動く代わりにぎくしゃくと動く視覚的欠陥を指します。モバイル開発では、Jankは単位時間あたりのスキップされたフレーム数(skipped frames)として測定されます。システムがVSyncのタイミングまでにフレームを準備できない場合、ディスプレイは前のフレームを繰り返します — 60Hzで16.6 msの停止が発生します。1回のフレームスキップは気づかれないかもしれませんが、3~5回の連続したフレームスキップは50~80 ms続く“途切れ”感を生み出し、ユーザーは明確に認識します。

Jankは、一定の速度で動作する必要があるアニメーション(フィードのスクロール、メニューを開くアニメーション、パララックス効果、画面間の遷移)にとって特に重要です。GoogleのUX調査(2024年)によると、スクロールセッションの3%以上でJank率が発生するアプリは、0.5%未満のアプリよりも22%多く1つ星レビューを受けています。Android VitalsツールはJankを自動的に追跡し、重要度(中程度、重大、致命的)に分類します。

Jankの主な原因

Jankの原因はいくつかのカテゴリに分類されます。1つ目はLayout Jank:Viewのサイズ変更、LayoutTransitionアニメーション、動的コンテンツ読み込みによる頻繁なrequestLayout()呼び出しによって発生します。requestLayoutが呼び出されるたびに、Viewサブツリー全体でMeasure + Layoutがトリガーされ、5~30 msかかる可能性があります。2つ目はDraw Jank:オーバードローと重いdrawableの使用に関連します。3つ目はThread Jank:同期的な操作(ファイル読み込み、メインスレッドでのデータベース操作、Bitmapデコード)によるメインスレッドのブロッキングです。

4つ目のカテゴリはGC Jank:ART/DalvikまたはSwift ARCでのガベージコレクション(Garbage Collection)です。ヒープに多くのオブジェクトが蓄積されると、GCは5~15 msのStop-The-Worldポーズを開始します。Androidでは、GCポーズはループ内での頻繁なアロケーション(onDraw()でのオブジェクト生成、アダプターでのアロケーション、未使用のラムダ式)時に最も頻繁に発生します。5つ目はIPC Jank:メインスレッドでのプロセス間通信(ContentProvider、Binder)です。6つ目はRendering Jank:最適でないシェーダーや大きなテクスチャによるGPUレンダリングの遅延です。

Jankのタイプ原因標準的な持続時間検出ツール
LayoutrequestLayout, relayout5~30 msPerfetto, Systrace
DrawOverdraw, 重いdrawable3~20 msGPU Profiling
Threadメインスレッドのブロッキング10~200 msAndroid Studio Profiler
GCGarbage Collection5~15 msMemory Profiler
RenderingGPU負荷10~50 msGPU Tracer, Xcode GPU

AndroidでのJank診断

Androidでは、Jankの診断はPerfettoシステムトレースから始まります。Perfettoはすべてのスレッド、CPU、GPU、スケジューラのアクティビティを記録します。Jankの明確な指標はChoreographer.doFrameとChoreographer.doCallbacksの行です:2つの連続するdoFrame呼び出しの間隔が16.6 msを超える場合、フレームがスキップされています。Perfettoは正確な原因(どのシステムコール、ロック、GCが遅延を引き起こしたか)を示します。Android Studio Profilerでは、CPU Profilerを通じて同様の機能が利用できます。

本番環境での自動Jank検出にはFrameMetricsAggregatorが使用されます — 各フレームの統計を収集し、セッションごとに集約するAPIです。Android 12+ではPerformanceHintManagerが登場しました — システムに目標フレームレートをヒントするAPIです。アプリが120 FPSシナリオで動作していることを示すと、システムはJankを防ぐためにCPU/GPU周波数を上げることができます。すべてのスキップされたフレームを簡単にログ記録するには、Choreographer.FrameCallbackにサブスクライブするだけで十分です。

ChoreographerによるJankログ記録

KotlinコードはChoreographer.FrameCallbackにサブスクライブし、遅延時間とともに各スキップされたフレームをログに記録します。コールバックは各VSyncで呼び出されます。

kotlin
class JankDetector {

    private val frameBudget = 16_666_666L
    private var previousFrameTime = 0L

    private val callback =
        Choreographer.FrameCallback { currentTime ->
            if (previousFrameTime != 0L) {
                val frameDuration =
                    currentTime - previousFrameTime
                val skippedFrames =
                    (frameDuration / frameBudget) - 1
                if (skippedFrames > 0) {
                    Log.w("Jank",
                        "Skipped $skippedFrames frames")
                }
            }
            previousFrameTime = currentTime
            Choreographer.getInstance()
                .postFrameCallback(this)
        }

    fun start() {
        Choreographer.getInstance()
            .postFrameCallback(callback)
    }
}

iOSでのJank診断

iOSでは、Jankの診断はCore Animationテンプレートを使用したInstrumentsで行われます。InstrumentsはリアルタイムのFPS、オフスクリーンレンダリングの数、ヒットテストを表示します。iOSでのJankの主な指標:Core Animationタイムラインの赤いバー(フレーム予算超過)、高いRenderer値(オフスクリーンレンダリングを示す)、低いFPSです。本番モニタリングでは、MetricKitがMXAnimatoryMetricメトリクスを含むレポートを収集します。これには平均FPS、P50およびP95フレーム時間が含まれます。

iOSでのネイティブJank診断には、タイムスタンプとtargetTimestampのチェックを備えたCADisplayLinkが含まれます。現在のタイムスタンプがtargetTimestampから大幅に遅れている場合、1つ以上のフレームがスキップされています。Appleはカスタムプロファイリングにos_signpostを使用することも推奨しています:フレームレンダリングの開始と終了にsignpost-intervalを配置し、Instrumentsでどの間隔が16.6 msを超えているかを確認します。SwiftUIでは、Jank診断にUIView.invalidateIntrinsicContentSizeが使用されます — このメソッドの頻繁な呼び出しは不安定なLayoutを示します。

CADisplayLinkによるJank検出

SwiftコードはCADisplayLinkを使用してスキップされたフレームを検出します。タイムスタンプとtargetTimestampの差が16.6 msを超える場合、Jankが記録されます。

swift
class JankMonitor {

    private var displayLink: CADisplayLink?
    private var totalJank = 0

    func start() {
        displayLink = CADisplayLink(
            target: self,
            selector: #selector(detectJank)
        )
        displayLink?.add(to: .current,
            forMode: .common)
    }

    @objc
    private func detectJank() {
        guard let link = displayLink else { return }
        let delay = link.targetTimestamp
            - link.timestamp
        if delay > 0.0167 {
            totalJank += 1
        }
    }
}

Jankプロファイリングツール

Jankのプロファイリングには、OS内蔵ツールとサードパーティSDKの両方が使用されます。Androidでは、主要なツールはPerfettoです(Systraceの後継)。Perfettoは最大30秒間のトレースを記録し、Webインターフェースui.perfetto.devで分析できます。Choreographerのアクティビティ、レンダリングスレッド(RenderThread)、GPUを含む正確なタイムラインを表示します。GPUの問題を詳細に分析するには、AGI(Android GPU Inspector)が使用され、フレーム時間だけでなく、シェーダー、ラスタライザー、テクスチャユニットなどの特定のGPUブロックの負荷も表示します。

iOSでは、同等のものはCore Animation、Metal System Trace、GPU Driverテンプレートを使用したInstrumentsです。Core AnimationはFPSとフレーム時間を表示し、Metal System Traceは各ドローコールまでのGPU作業を表示します。負荷のかかる実際のデバイスでのプロファイリングには、Firebase Performance(Screen Renderingメトリクスを収集)とSentry(Jank時にスタックトレースをキャプチャ)が使用されます。新しいAndroid 15 Performance Hint APIにより、開発者はシステムにどのフレームが重要かを伝え、Jankが近づいたときにシステムから警告を受け取ることができます。

本番環境でのFrameMetricsAggregator

Kotlinコードは、セッション全体のフレーム統計を収集するためにFrameMetricsAggregatorを使用します。アグリゲーターを停止した後、スキップされたフレーム数が出力されます。

kotlin
class JankAggregator(private val activity: Activity) {

    private val aggregator = FrameMetricsAggregator()

    fun startCollection() {
        aggregator.add(activity.window)
    }

    fun stopAndReport() {
        aggregator.remove()
        val result = aggregator.getMetrics()
        val totalFrames = result
            ?.get(FrameMetrics.TOTAL_DURATION)
            ?.size ?: 0
        val jankFrames = result
            ?.get(FrameMetrics.TOTAL_DURATION)
            ?.count { it > 16_666_666L} ?: 0
        Log.d("JankReport",
            "Jank ratio: \${jankFrames * 100 / totalFrames}%")
    }
}

フレームの途切れを解消する方法

Jankを解消するには、そのタイプに応じたテクニックの組み合わせが必要です。Layout Jankの場合:深い階層をConstraintLayout/Compose/SwiftUIに置き換え、mergeタグを使用し、アニメーションでのrequestLayoutを避けます。Draw Jankの場合:Debug GPU Overdrawを使用して4x+のオーバードローを検出し、重いdrawableをベクターグラフィックス(VectorDrawable/PDF)に置き換え、ハードウェアレイヤーは注意して使用します — レンダリングは高速化しますが、GPUメモリを多く消費します。Thread Jankの場合:すべてのI/O操作、データベース作業、Bitmapデコードをバックグラウンドスレッドに移動し、適切なDispatcherを使用したKotlin Coroutines、またはSchedulers.io()を使用したRxJavaを使用します。

GC Jankの場合:onDraw()とgetView()でのアロケーションを最小限に抑え、オブジェクトプール(ObjectPool)を使用し、for-eachをインデックス付きforに置き換え、Kotlinのcopy()付きイミュータブルdata classは注意して使用します — copyは新しいオブジェクトを作成します。IPC Jankの場合:App Startupを介してContentProviderを遅延初期化し、Binder呼び出しをバックグラウンドスレッドに移動します。Rendering Jankの場合:テクスチャサイズを最大画面解像度まで縮小し、ASTCまたはETC2圧縮を使用し、過剰なシェーダーコンパイルを回避します(シェーダーは事前にコンパイル)。包括的な解決策は、CIでの定期的なPerfetto/InstrumentsプロファイリングとJank回帰の追跡です。

アンチJankパターン:非同期レイアウト

Kotlinコードは、reportFullyDrawn後に画面上にデータを非同期で読み込むことを示しています。これにより、重い処理が最初のフレームをブロックしません。コールバックはユーザーがインターフェースを表示した後に呼び出されます。

kotlin
class JankSafeLoader {

    suspend fun loadAfterFirstFrame(
        activity: Activity
    ) {
        // 最初のフレームがすでにレンダリングされていることを保証
        if (Build.VERSION.SDK_INT >= 29) {
            activity.reportFullyDrawn()
        }

        // 重い読み込み — 最初のフレームの後
        withContext(Dispatchers.IO) {
            val data = fetchHeavyData()
            withContext(Dispatchers.Main) {
                updateUI(data)
            }
        }
    }
}

よくある質問

モバイルアプリのJankとは?

Jankとは、スキップされたレンダリングフレームで、アニメーションに目に見える途切れやぎくしゃく感として現れます。フレームの準備時間が時間予算(60 FPSで16.6 ms)を超えると発生します。

Jankの主な原因は?

Layout Jank(頻繁なrequestLayout)、Draw Jank(オーバードロー)、Thread Jank(メインスレッドのブロッキング)、GC Jank(ガベージコレクション)、IPC Jank(Binder呼び出し)、Rendering Jank(重いシェーダー)。

AndroidでJankを診断するには?

システムトレースにはPerfetto、フレームフェーズ分析にはGPU Profiling、本番モニタリングにはFrameMetricsAggregatorを使用します。Android Studioでは — Deep Java Trace付きのCPU Profiler。

iOSでJankを測定するには?

Instrumentsを使用し、Core AnimationまたはMetal System Traceテンプレートを使用します。本番環境では — MXAnimatoryMetricを使用したMetricKit。プログラム的には — timestampとtargetTimestampの差をチェックするCADisplayLink。

どの程度のJank率が重要と見なされますか?

Googleによると、スクロールセッションの3%を超えるJank率(100回のスクロール中3回に途切れがある)は、否定的なレビューが22%増加することにつながります。目標率はスクロールセッションの0.5%未満です。

まとめ

  • Jank — スキップされたフレームで、モバイルアプリのアニメーションに目に見える途切れを引き起こします。
  • 主な原因:Layout Jank、Draw Jank、Thread Jank、GC Jank、IPC Jank、Rendering Jank。
  • AndroidでのJank診断 — Perfetto、GPU Profiling、FrameMetricsAggregatorを使用。
  • iOSでのJank診断 — Instruments、CADisplayLink、MetricKitを使用。
  • Jank解消には以下が必要:フラットな階層、バックグラウンドスレッド、最小限のアロケーション、キャッシング。
  • 目標Jank率 — 途切れのあるスクロールセッションを0.5%未満に。
  • CIでの定期的なプロファイリングにより、本番環境に到達する前にパフォーマンスの回帰を防ぎます。

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください