Затеже у развоју — шта је то, узроци и методе оптимизације

Аутор: IT Sectr Објављено: 2026-07-28 Време читања: 8 мин

Затеже — то је кориснички опис ситуације када мобилна апликација ради споро и нестабилно: час реагује нормално, час изненада застане на неколико секунди. У техничком контексту „затеже” означава комбинацију лагова и микрозастајања изазвану честим GC паузама, блокирањем главне нити синхроним операцијама и неоптималним структурама података. Према Android Performance Benchmarking Guide, смањење времена одзива са 300 ms на 100 ms повећава задржавање корисника за 25%. Дијагностика затезања захтева комбинацију CPU и Memory профилисања са анализом учесталости сакупљања смећа.

Главно

  • Затеже — непостојано успоравање рада апликације, које се смењује са нормалним перформансама
  • Главни узроци — честе GC паузе, синхроне операције у UI нити, велика количина података у адаптерима без пагинације
  • Дијагностика захтева CPU Profiler за проналажење блокова и Memory Profiler за анализу учесталости и трајања GC
  • Отклањање укључује увођење пагинације (Paging 3), оптимизацију SQL упита кроз Room и пребацивање тешких задатака у WorkManager
  • Превенција — Benchmark Baseline Profiles, AOT компилација, минимизација алокација у врућим деловима кода

Шта значи „затеже” у мобилном развоју

Затеже — неформални термин којим корисници описују субјективно спор рад апликације. За разлику од лага, који се манифестује као константно кашњење, затезање су неправилна застајања: апликација може савршено радити неколико секунди, а затим се „замислити” на 1–3 секунде.

Техничка карактеристика појаве

Са становишта профилисања, затеже се манифестује као серија пропуштених кадрова (jank) са вршним кашњењима већим од 100 ms. На графикону FPS то изгледа као оштри падови: 60 → 20 → 55 → 10 кадрова у секунди. За разлику од лага са равномерно ниским FPS, затезање има изражену варијабилност.

Корисничка перцепција

Када апликација затеже, корисник не разуме логику успоравања: екран се може глатко померати, а затим изненада стати на секунду. То изазива фрустрацију и смањује поверење у апликацију. Према Google-у, 53% корисника напушта сајт или апликацију ако учитавање траје дуже од 3 секунде.

Узроци изненадних успоравања у апликацијама

Непостојан карактер затезања указује на то да је проблем изазван догађајним факторима, а не сталним преоптерећењем. Размотримо типичне сценарије.

GC паузе при алокацији објеката

На Android у ART окружењу сакупљање смећа зауставља све нити апликације. Ако се у коду ствара много привремених објеката — на пример, при сваком позиву onBindViewHolder ствара се нови String кроз конкатенацију — GC се покреће чешће. Пауза може трајати 5–50 ms у зависности од величине хеапа и генерације објеката. Корисник то осећа као изненадно „размишљање”.

Синхрони SQL упити у UI нити

Room на Android и Core Data на iOS подржавају асинхроне упите, али програмери често позивају getValue() или извршавају упит кроз runBlocking ради једноставности. Тежак SELECT са join-овима на табели од 10 000 редова може трајати 200–500 ms, потпуно блокирајући UI за то време.

Декодирање слике без downscale

Учитавање слике са камере (12 Mp, 4000x3000 px) без скалирања траје до 200 ms за декодирање у Bitmap. Ако се слике учитавају асинхроно, али без пула нити са ограничењем, истовремено покретање 5–6 декодирања може преоптеретити CPU, изазивајући мигрирајућа успоравања.

  • Android — конкатенација стрингова у петљама, стварање објеката у врућим путањама, Bitmap без inSampleSize
  • iOS — autorelease pool-ови са великим бројем објеката, imageWithContentsOfFile без скалирања, синхрони URLSession
  • Cross-platform — JSON парсинг у UI нити, учитавање података на главној нити са чекањем одговора сервера

Како дијагностиковати застајања на Android и iOS

Дијагностика непостојаних успоравања је тежа од дијагностике сталних лагова, јер се проблем можда неће поновити при сваком покретању. Потребно је прикупљање статистике током дужег периода.

Memory Profiler са снимањем GC догађаја

Android Studio Memory Profiler показује не само коришћење меморије, већ и GC догађаје: учесталост, тип (Concurrent, Full), трајање. Ако се GC јавља чешће од 1 пута у 5 секунди у мирном стању — то је знак прекомерне алокације. Снимање heap dump-а у тренутку затезања омогућава да се види који објекти заузимају меморију.

Xcode Instruments са Allocation Tracking

На iOS користите шаблон Allocations у Instruments-у за праћење стварања и ослобађања објеката. Укључите генерације (Generations) — оне омогућавају снимање хеапа између акција и увид у то који објекти остају у меморији. Перзистентни објекти који се не ослобађају — извор акумулације меморије и каснијих пауза.

JankStats API на Android

JankStats — Android библиотека која прикупља метрике пропуштених кадрова у реалном времену. Везује сваки jank за тренутни сценарио (нпр. „скроловање листе”, „отварање екрана”), што омогућава да се разуме на којој конкретној радњи настаје затезање.

Пример интеграције JankStats за праћење застајања на Android:

kotlin
class MainActivity : AppCompatActivity() {
    private lateinit var jankStats: JankStats

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        jankStats = JankStats.create(this.window.decorView) { frameData ->
            if (frameData.isJank()) {
                Log.w("Jank", "Duration=${frameData.durationMs}ms")
            }
        }
    }
}

Методе отклањања спорог рада

Отклањање затезања захтева циљани рад са сваким узроком. Не постоји универзално решење — потребна је анализа конкретних профила перформанси.

Увођење пагинације кроз Paging 3

Ако листа садржи 1000+ елемената и сви се учитавају одједном — то је гарантовано затезање. Paging 3 на Android и NSFetchedResultsController на iOS учитавају податке у порцијама током скроловања. Корисник види само првих 10–20 елемената, остали се учитавају у позадини.

Оптимизација SQL упита и индекса

Room омогућава профилисање упита кроз Inspection Tool у Android Studio: види се време извршења, број враћених редова и план упита. Додавање индекса на колоне WHERE и ORDER BY може смањити време упита са 300 ms на 5 ms. На iOS аналогну проверу врши Core Data Profiler у Instruments-у.

Пребацивање задатака у WorkManager

Позадинске синхронизације, учитавање фајлова, обрада података — све то треба да се извршава кроз WorkManager (Android) или Background Tasks (iOS). Ако се синхронизација покреће у UI нити, апликација ће затезати током извршења. WorkManager гарантује извршење у позадинској нити узимајући у обзир стање батерије и мреже.

Пример позадинске синхронизације кроз WorkManager на Android:

kotlin
class SyncWorker(context: Context, params: WorkerParameters)
    : CoroutineWorker(context, params) {

    override suspend fun doWork(): Result {
        return try {
            Log.d("Sync", "Синхронизација података у позадинској нити")
            syncData()
            Result.success()
        } catch (e: Exception) {
            Result.retry()
        }
    }
}

Превенција затезања у фази развоја

Затезање се може спречити у фази писања кода, праћењем принципа ефикасног рада са меморијом и нитима.

Baseline Profiles за AOT компилацију

Baseline Profiles — листа класа и метода које Android компилира унапред (AOT), а не JIT. Без профила, сваки нови екран се компилира при првом отварању, изазивајући кашњење од 100–500 ms. Припремите Baseline Profile за кључне екране и укључите генерисање у Gradle-у кроз baseline-profile-gradle-plugin.

Минимизација алокација у врућим путањама

Hot path — код који се извршава при сваком кадру: onBindViewHolder, draw, layoutSubviews. Избегавајте стварање објеката у овим методама: користите pool објеката, StringBuilder уместо конкатенације, кеширајте форматиране стрингове и форматере. Свака додатна алокација приближава следећи GC.

Профилисање кроз Baseline Profiles у CI

Додајте у CI pipeline покретање Macrobenchmark са сценаријом скроловања листе и отварања екрана. Поставите праг: 99. перцентил времена кадра не сме да прелази 16 ms. Ако је праг прекорачен — build се одбија до оптимизације.

  • Android — Baseline Profiles, Macrobenchmark, JankStats, StrictMode са penaltyDeath
  • iOS — MetricKit, os_signpost, XCTMetric, Main Thread Checker у Debug шеми
  • Општи приступ — редовно профилисање, code review са фокусом на алокације у врућим путањама

Често постављана питања

По чему се затезање разликује од обичног лага?

Лаг — стално кашњење (нпр. 200 ms на сваки притисак). Затеже — непостојано: апликација ради нормално, затим изненада успорава 1–3 секунде, па опет нормално. Узрок — догађајни фактори попут GC пауза или синхроних упита ка бази података.

Како измерити учесталост GC пауза на Android?

Користите Memory Profiler у Android Studio: картица Memory приказује GC догађаје са трајањем. За производни мониторинг прикључите Firebase Performance Monitoring са прилагођеним траговима. На iOS укључите Malloc Debug и означите генерације алокација у Instruments-у.

Може ли затезање бити изазвано мрежним упитима?

Индиректно — да. Ако одговор сервера долази са кашњењем, а UI га чека синхроно, апликација застаје. Ако је упит асинхрон, али се обрада одговора обавља у UI нити — то ће такође изазвати затезање. Решење — асинхрона обрада са corutinama и индикаторима напретка.

Како Kotlin Multiplatform утиче на перформансе?

При неправилној употреби KMP може генерисати сувишне омотаче за интероперабилност. На iOS то повећава учесталост алокација и, последично, ARC паузе. Користите @ObjCName, оптимизујте expect/actual и избегавајте честе позиве заједничког кода из врућих путања UI.

Помаже ли повећање хеапа на Android?

Повећање хеапа кроз android:largeHeap="true" одлаже GC, али не отклања узрок алокација. Када GC ипак покрене, пауза ће бити дужа јер треба обићи више објеката. Решење — смањити број алокација, а не проширивати хеап.

Закључци

  • Затеже — непостојано успоравање апликације изазвано догађајним факторима (GC паузе, синхрони упити, декодирање слика)
  • Дијагностика захтева Memory Profiler, JankStats на Android и Allocation Tracking у Instruments на iOS
  • Главни узроци — честе GC паузе, одсуство пагинације, неоптимални SQL упити и синхрона обрада у UI нити
  • Отклањање — Paging 3, WorkManager, оптимизација индекса базе података, скалирање слика и минимизација алокација
  • Превенција — Baseline Profiles, Macrobenchmark, StrictMode, code review са провером врућих путања
  • Алати — JankStats, Firebase Performance, MetricKit за производни мониторинг застајања
  • Препорука: уведите редовно покретање Macrobenchmark у CI са прагом од 16 ms на 99. перцентилу кадрова

Развићемо мобилну апликацију под кључ

IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође