Jank για εφαρμογές κινητών — τι είναι, αιτίες και διόρθωση

Συγγραφέας: IT Sectr Δημοσιεύτηκε: 2026-04-01 Χρόνος ανάγνωσης: 10 λεπ

Jank — είναι ένας όρος που υποδηλώνει αισθητά τραυλίσματα ή “κολλήματα” στην κίνηση της διεπαφής, που προκαλούνται από την παράλειψη μεμονωμένων καρέ. Σε εφαρμογές κινητών, το Jank εμφανίζεται όταν ο χρόνος απόδοσης ενός καρέ υπερβαίνει τον προϋπολογισμό που κατανέμεται από τον ρυθμό ανανέωσης της οθόνης. Σύμφωνα με το Android Developers, 2025, το Jank είναι η κύρια αιτία της υποκειμενικής αίσθησης “καθυστέρησης” — η εφαρμογή μπορεί να είναι λειτουργικά τέλεια, αλλά ο χρήστης την αντιλαμβάνεται ως αργή λόγω ασταθούς FPS.

Κύρια σημεία

  • Jank — παραλειπόμενα καρέ, αισθητά ως τραυλίσματα της κίνησης.
  • Κύρια αιτία — υπέρβαση του χρονικού προϋπολογισμού ανά καρέ (16.6 ms για 60 FPS).
  • Το Jank προκύπτει από βαρύ Layout, μεγάλο GC, μπλοκάρισμα του main thread ή overdraw.
  • Για διάγνωση χρησιμοποιούνται τα FrameTimeline (Android) και Instruments (iOS).
  • Η διόρθωση του Jank αυξάνει το NPS και τη διατήρηση χρηστών κατά 15–25%.

Τι είναι το Jank

Jank — είναι ένας όρος από τον τομέα των γραφικών υπολογιστή που υποδηλώνει ένα οπτικό ελάττωμα κατά το οποίο η κίνηση γίνεται με τραντάγματα αντί για ομαλή ολίσθηση. Στην ανάπτυξη κινητών, το Jank μετράται ως ο αριθμός των παραλειπόμενων καρέ (skipped frames) ανά μονάδα χρόνου. Εάν το σύστημα δεν προλάβει να προετοιμάσει ένα καρέ μέχρι τη στιγμή VSync, η οθόνη επαναλαμβάνει το προηγούμενο καρέ — δημιουργείται μια παύση 16.6 ms στα 60 Hz. Ένα παραλειπόμενο καρέ μπορεί να είναι απαρατήρητο, αλλά μια σειρά 3–5 συνεχόμενων παραλειπόμενων καρέ δημιουργεί μια αίσθηση “καθυστέρησης” 50–80 ms, την οποία ο χρήστης αντιλαμβάνεται καθαρά.

Το Jank είναι ιδιαίτερα κρίσιμο για κινήσεις που πρέπει να λειτουργούν με σταθερή ταχύτητα: κύλιση λίστας, κίνηση ανοίγματος μενού, εφέ παράλλαξης, μεταβάσεις μεταξύ οθονών. Σύμφωνα με έρευνα UX της Google (2024), μια εφαρμογή με δείκτη Jank άνω του 3% των συνεδριών κύλισης λαμβάνει 22% περισσότερες κριτικές ενός αστεριού από μια εφαρμογή με δείκτη κάτω του 0.5%. Το εργαλείο Android Vitals παρακολουθεί αυτόματα το Jank και το ταξινομεί ανάλογα με τη σοβαρότητα: moderate, severe και critical.

Κύριες αιτίες του Jank

Οι αιτίες του Jank χωρίζονται σε διάφορες κατηγορίες. Πρώτη — Layout Jank: προκαλείται από συχνές κλήσεις requestLayout() λόγω αλλαγής μεγεθών View, κινήσεων LayoutTransition ή δυναμικής φόρτωσης περιεχομένου. Κάθε κλήση requestLayout ενεργοποιεί Measure + Layout για ολόκληρο το υποδέντρο View, το οποίο μπορεί να διαρκέσει 5–30 ms. Δεύτερη — Draw Jank: σχετίζεται με overdraw και χρήση βαρέων drawable. Τρίτη — Thread Jank: μπλοκάρισμα του main thread λόγω σύγχρονων λειτουργιών — φόρτωση αρχείων, εργασία με βάση δεδομένων στο κύριο νήμα, αποκωδικοποίηση Bitmap.

Τέταρτη κατηγορία — GC Jank: garbage collection στο ART/Dalvik ή Swift ARC. Όταν συσσωρεύονται πολλά αντικείμενα στο heap, το GC ενεργοποιεί μια παύση Stop-The-World διάρκειας 5–15 ms. Στο Android, οι παύσεις GC εμφανίζονται συχνότερα σε συχνές δεσμεύσεις μνήμης σε βρόχους: δημιουργία αντικειμένων σε onDraw(), δεσμεύσεις σε προσαρμογείς, αχρησιμοποίητες εκφράσεις lambda. Πέμπτη — IPC Jank: επικοινωνία μεταξύ διεργασιών (ContentProvider, Binder) στο κύριο νήμα. Έκτη — Rendering Jank: αργή απόδοση GPU λόγω μη βέλτιστων shader ή υφών μεγάλου μεγέθους.

Τυπική διάρκεια
Τύπος JankΑιτίαΕργαλείο αναζήτησης
LayoutrequestLayout, relayout5–30 msPerfetto, Systrace
DrawOverdraw, βαρύ drawable3–20 msGPU Profiling
ThreadΜπλοκάρισμα main thread10–200 msAndroid Studio Profiler
GCGarbage Collection5–15 msMemory Profiler
RenderingΦόρτωση GPU10–50 msGPU Tracer, Xcode GPU

Διάγνωση Jank στο Android

Στο Android, η διάγνωση του Jank ξεκινά με το σύστημα ιχνηλάτησης Perfetto. Το Perfetto καταγράφει τη δραστηριότητα όλων των νημάτων, CPU, GPU και του χρονοπρογραμματιστή. Ένας σαφής δείκτης Jank είναι οι γραμμές Choreographer.doFrame και Choreographer.doCallbacks: εάν το διάστημα μεταξύ δύο διαδοχικών κλήσεων doFrame υπερβαίνει τα 16.6 ms, το καρέ παραλείπεται. Το Perfetto δείχνει την ακριβή αιτία — ποιο system call, lock ή GC προκάλεσε την καθυστέρηση. Στο Android Studio Profiler, παρόμοια λειτουργία είναι διαθέσιμη μέσω του CPU Profiler.

Για αυτόματη ανίχνευση Jank σε παραγωγή χρησιμοποιείται το FrameMetricsAggregator — ένα API που συλλέγει στατιστικά για κάθε καρέ και τα συγκεντρώνει ανά συνεδρία. Στο Android 12+ εμφανίστηκε το PerformanceHintManager — ένα API για υποδείξεις στο σύστημα σχετικά με τον στοχευόμενο ρυθμό καρέ. Εάν η εφαρμογή υποδείξει ότι λειτουργεί σε σενάριο 120 FPS, το σύστημα μπορεί να αυξήσει τη συχνότητα CPU/GPU για την πρόληψη του Jank. Για απλή καταγραφή όλων των παραλειπόμενων καρέ, αρκεί η εγγραφή στο Choreographer.FrameCallback.

Καταγραφή Jank μέσω Choreographer

Ο κώδικας 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",
                        "Παραλείφθηκαν $skippedFrames καρέ")
                }
            }
            previousFrameTime = currentTime
            Choreographer.getInstance()
                .postFrameCallback(this)
        }

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

Διάγνωση Jank στο iOS

Στο iOS, η διάγνωση του Jank πραγματοποιείται μέσω του Instruments με το πρότυπο Core Animation. Το Instruments δείχνει το FPS σε πραγματικό χρόνο, τον αριθμό των offscreen-render και τα hit-test. Οι κύριοι δείκτες Jank στο iOS: κόκκινες στήλες στη χρονική κλίμακα Core Animation (υπέρβαση προϋπολογισμού καρέ), υψηλός δείκτης Renderer (σημαίνει offscreen rendering) και χαμηλό FPS. Για παρακολούθηση παραγωγής, το MetricKit συλλέγει αναφορές με τη μετρική MXAnimatoryMetric, η οποία περιλαμβάνει μέσο FPS, P50 και P95 χρόνο καρέ.

Η εγγενής διάγνωση Jank στο iOS περιλαμβάνει το CADisplayLink με έλεγχο timestamp και targetTimestamp. Εάν το τρέχον timestamp υστερεί σημαντικά από το targetTimestamp, ένα ή περισσότερα καρέ έχουν παραλειφθεί. Η Apple συνιστά επίσης τη χρήση os_signpost για προσαρμοσμένη προφίλ: τοποθετήστε signpost-interval στην αρχή και στο τέλος της απόδοσης καρέ και ελέγξτε στο Instruments ποια διαστήματα υπερβαίνουν τα 16.6 ms. Στο SwiftUI, για διάγνωση Jank χρησιμοποιείται το UIView.invalidateIntrinsicContentSize — η συχνή κλήση αυτής της μεθόδου υποδηλώνει ασταθές Layout.

CADisplayLink για ανίχνευση Jank

Ο κώδικας Swift ανιχνεύει παραλειπόμενα καρέ μέσω CADisplayLink. Εάν η διαφορά μεταξύ timestamp και 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 χρησιμοποιούνται τόσο τα ενσωματωμένα εργαλεία του λειτουργικού συστήματος όσο και SDK τρίτων. Στο Android, το βασικό εργαλείο είναι το Perfetto (αντικατέστησε το Systrace). Το Perfetto επιτρέπει την εγγραφή ιχνηλατήσεων έως 30 δευτερόλεπτα και την ανάλυσή τους μέσω της διεπαφής ιστού ui.perfetto.dev. Δείχνει την ακριβή χρονογραμμή με τη δραστηριότητα του Choreographer, των νημάτων απόδοσης (RenderThread) και της GPU. Για λεπτομερή ανάλυση προβλημάτων GPU χρησιμοποιείται το AGI (Android GPU Inspector), το οποίο δείχνει όχι μόνο τον χρόνο καρέ αλλά και τη φόρτωση συγκεκριμένων μπλοκ GPU — shader, ραστεροποιητή, μπλοκ υφής.

Στο iOS, το αντίστοιχο είναι το Instruments με τα πρότυπα Core Animation, Metal System Trace και GPU Driver. Το Core Animation δείχνει FPS και χρόνο καρέ, το Metal System Trace — εργασία GPU με λεπτομέρεια έως κάθε draw call. Για προφίλ σε πραγματικές συσκευές υπό φόρτο χρησιμοποιούνται τα Firebase Performance (συλλέγει μετρική Screen Rendering) και Sentry(καταγράφει stack trace στο Jank). Το νέο API Android 15 Performance Hint επιτρέπει στον προγραμματιστή να υποδείξει στο σύστημα ποια καρέ είναι σημαντικά και να λαμβάνει προειδοποιήσεις από το σύστημα όταν πλησιάζει το Jank.

FrameMetricsAggregator σε παραγωγή

Ο κώδικας Kotlin χρησιμοποιεί το FrameMetricsAggregator για συλλογή στατιστικών καρέ ανά συνεδρία. Μετά τη διακοπή του aggregator, εμφανίζεται ο αριθμός των παραλειπόμενων καρέ.

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: ${jankFrames * 100 / totalFrames}%")
    }
}
            

Μέθοδοι διόρθωσης τραυλισμάτων καρέ

Η διόρθωση του Jank απαιτεί συνδυασμό μεθόδων ανάλογα με τον τύπο του. Για Layout Jank: αντικατάσταση βαθιών ιεραρχιών με ConstraintLayout/Compose/SwiftUI, χρήση merge-tags, αποφυγή requestLayout σε κινήσεις. Για Draw Jank: χρήση Debug GPU Overdraw για εύρεση 4x+ overdraw, αντικατάσταση βαρέων drawable με διανυσματικά (VectorDrawable/PDF), προσεκτική χρήση hardware layers — επιταχύνουν την απόδοση αλλά καταναλώνουν περισσότερη μνήμη GPU. Για Thread Jank: μεταφορά όλων των λειτουργιών I/O, εργασίας με βάση δεδομένων και αποκωδικοποίησης Bitmap σε νήματα παρασκηνίου, χρήση Kotlin Coroutines με σωστό Dispatcher ή RxJava με Schedulers.io().

Για GC Jank: ελαχιστοποίηση δεσμεύσεων σε onDraw() και getView(), χρήση object pool (ObjectPool), αντικατάσταση for-each με indexed for, προσεκτική χρήση immutable data class σε Kotlin με copy() — το copy δημιουργεί νέο αντικείμενο. Για IPC Jank: τεμπέλικη αρχικοποίηση ContentProvider μέσω App Startup, μεταφορά κλήσεων Binder σε νήμα παρασκηνίου. Για Rendering Jank: μείωση μεγέθους υφών στη μέγιστη ανάλυση οθόνης, χρήση συμπίεσης ASTC ή ETC2, αποφυγή περιττής shader compilation (μεταγλώττιση shader εκ των προτέρων). Ολοκληρωμένη λύση — τακτική εκτέλεση προφίλ Perfetto/Instruments στο CI και παρακολούθηση παλινδρομήσεων Jank.

Μοτίβο Anti-Jank: Async Layout

Ο κώδικας Kotlin παρουσιάζει ασύγχρονη φόρτωση δεδομένων στην οθόνη μετά το reportFullyDrawn, ώστε η βαριά εργασία να μην μπλοκάρει το πρώτο καρέ. Το callback καλείται αφού ο χρήστης δει τη διεπαφή.

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 — είναι παραλειπόμενα καρέ απόδοσης που εκδηλώνονται ως αισθητά τραυλίσματα ή τραντάγματα της κίνησης. Συμβαίνει όταν ο χρόνος προετοιμασίας καρέ υπερβαίνει τον χρονικό προϋπολογισμό (16.6 ms για 60 FPS).

Ποιες είναι οι κύριες αιτίες του Jank;

Layout Jank (συχνές requestLayout), Draw Jank (overdraw), Thread Jank (μπλοκάρισμα main thread), GC Jank (garbage collection), IPC Jank (κλήσεις Binder) και Rendering Jank (βαριά shader).

Πώς γίνεται διάγνωση του Jank στο Android;

Χρησιμοποιήστε το Perfetto για ιχνηλάτηση συστήματος, GPU Profiling για ανάλυση φάσεων καρέ και FrameMetricsAggregator για παρακολούθηση παραγωγής. Στο Android Studio — CPU Profiler με Deep Java Trace.

Πώς μετράται το Jank στο iOS;

Μέσω Instruments με το πρότυπο Core Animation ή Metal System Trace. Για παραγωγή — MetricKit με MXAnimatoryMetric. Προγραμματιστικά — CADisplayLink με έλεγχο διαφοράς timestamp και targetTimestamp.

Τι ποσοστό Jank θεωρείται κρίσιμο;

Σύμφωνα με την Google, δείκτης Jank άνω του 3% των συνεδριών κύλισης (3 στα 100 scroll περιέχουν τραύλισμα) οδηγεί σε αύξηση των αρνητικών κριτικών κατά 22%. Στόχος — λιγότερο από 0.5% των συνεδριών κύλισης.

Σύνοψη

  • Jank — παραλειπόμενα καρέ που προκαλούν ορατό τραύλισμα κίνησης σε εφαρμογές κινητών.
  • Κύριες αιτίες: Layout Jank, Draw Jank, Thread Jank, GC Jank, IPC Jank και Rendering Jank.
  • Διάγνωση Jank στο Android — μέσω Perfetto, GPU Profiling και FrameMetricsAggregator.
  • Διάγνωση Jank στο iOS — μέσω Instruments, CADisplayLink και MetricKit.
  • Η διόρθωση Jank απαιτεί συνδυασμό: επίπεδες ιεραρχίες, νήματα παρασκηνίου, ελάχιστες δεσμεύσεις, προσωρινή αποθήκευση.
  • Στόχος δείκτη Jank — λιγότερο από 0.5% συνεδρίες κύλισης με τραυλίσματα.
  • Η τακτική προφίλ στο CI αποτρέπει παλινδρομήσεις απόδοσης πριν από την κυκλοφορία.

Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση

Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.

Συζήτηση έργου

Διαβάστε επίσης