Heap Dump: шта је то, анализа хеапа и отклањање цурења меморије

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

Heap Dump (дамп хеапа) — снимак динамичке меморије апликације који садржи потпуне информације о свим живим објектима: њиховим класама, величинама, међусобним референцама и доступности од коренских чворова (GC roots). Heap Dump је основни алат за анализу цурења меморије и оптимизацију потрошње ресурса. Према Android Developers, анализа heap dump-ова омогућава откривање до 95% цурења меморије, укључујући цикличне референце, заборављене listener-е и неослобођене статичке референце.

Главно

  • Heap Dump — снимак целе динамичке меморије апликације са информацијама о сваком објекту и референцама између њих.
  • Android Studio Memory Profiler омогућава снимање heap dump-а у реалном времену за Java и Kotlin апликације.
  • Xcode Instruments пружа алат Allocations за креирање и анализу heap dump-ова на iOS/macOS-у.
  • Shallow и retained size су кључне метрике: shallow — величина самог објекта, retained — величина објекта плус сви објекти које он држи.
  • Анализа heap dump-а укључује претрагу dominator tree-а, највећих retained objects и најкраћих путања до GC roots-а.

Шта је heap dump и зашто је потребан

Heap dump представља потпун дамп хеапа (heap) виртуелне машине — области меморије где се смештају сви динамички креирани објекти. У Java и Kotlin-у то је Dalvik/ART на Android-у, у Swift и Objective-C-у — ARC-управљани хеап на iOS-у. Heap dump бележи сваки објекат, његову класу, величину, поља, референце на друге објекте и заставице доступности од GC roots-а (стек променљиве, статичка поља, JNI референце).

Основни циљ heap dump-а је откривање цурења меморије. Цурење настаје када апликација наставља да држи референце ка објектима који више нису потребни, спречавајући њихово сакупљање од стране garbage collector-а (или ослобађање путем ARC-а). Типични узроци: listener-и догађаја који нису одјављени при уништењу activity; синглтони са референцама на контекст; затварања (closures) која хватају self; статичке колекције у које се додају подаци без брисања. Heap dump даје прецизну слику: који објекти су „живи“, који су сувишни и ко тачно референцира на њих.

Према подацима Google I/O, више од 60% извештаја о падовима Android апликација је повезано са OutOfMemoryError, а у 80% случајева основни узрок је цурење меморије које се открива путем heap dump-а. За iOS апликације ситуација је слична: цурења узрокована retain cycles-има су један од честих узрока падова који се откривају кроз Allocations instrument у Xcode-у.

Када је потребан heap dump

Heap dump треба извршити код следећих симптома: апликација троши меморију линеарно при понављајућим радњама (прелажење напред-назад између екрана); након завршетка рада екрана меморија се не враћа на почетни ниво; јављају се OutOfMemoryError или упозорења memory warning на iOS-у; апликација се прекида због прекорачења ограничења меморије (EXC_RESOURCE_RESOURCE на iOS-у). Редовно прикупљање heap dump-ова је део протокола инжењерске културе у великим мобилним пројектима, попут Instagram-а и Spotify-ја.

Heap dump у Android Studio: добијање и анализа

Android Studio пружа Memory Profiler — уграђени алат за снимање heap dump-а у реалном времену. Доступан је путем View → Tool Windows → Profiler. Након покретања апликације, изаберите сесију, пређите на картицу Memory и кликните Dump Java Heap. Android Studio зауставља апликацију, изводи дамп ART хеапа и учитава резултат за анализу. Датотека дампа има формат .hprof — стандард HPROF компатибилан са већином анализатора меморије.

Након учитавања дампа, Android Studio приказује табелу објеката са колонама: Allocations (број инстанци), Native Size (меморија ван ART хеапа), Shallow Size (меморија самог објекта), Retained Size (меморија објекта са целим подграфом). Филтрирање по имену класе, сортирање по retained size и претрага по пакетима омогућавају брзо проналажење проблематичних области.

kotlin
// Типично цурење — listener није одјављен у onDestroy-у
class MainActivity : AppCompatActivity() {
    private val sensorManager by lazy {
        getSystemService(SENSOR_SERVICE) as SensorManager
    }
    private val listener = MySensorListener()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        sensorManager.registerListener(listener,
            sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT),
            SensorManager.SENSOR_DELAY_NORMAL)
    }

    override fun onDestroy() {
        super.onDestroy()
        // ❌ Пропуштен sensorManager.unregisterListener(listener)
        // → Activity неће бити сакупљена од стране GC-а, heap dump ће показати цурење
    }
}

Анализа dominator tree-а у Android Studio

Картица Dominator Tree приказује објекте који држе највећу количину меморије. Ако се објекат избрише из dominator tree-а, сва меморија коју држи постаје доступна за сакупљање. Ово је кључни алат: уместо прегледа хиљада објеката, фокусирате се на 10–20 који контролишу 80–90% меморије. Према Google-у, анализа dominator tree-а је најефикаснији начин за проналажење тачке цурења, смањујући време анализе са сати на минуте.

Heap dump у Xcode Instruments: Allocations и Leaks

Xcode Instruments пружа два алата за рад са heap dump-ом: Allocations — снимање дампа хеапа са графиконом потрошње у реалном времену; Leaks — аутоматско проналажење цурења анализом retain cycles-а. Allocations приказује све објекте у хеапу, њихову величину, број креирања (allocations) и ослобађања (deallocations). Разлика између броја креирања и ослобађања за одређену класу указује на потенцијално цурење.

Снимање heap dump-а у Allocations-у се врши дугметом Snapshot Memory — алат зауставља апликацију и снима потпун дамп. Након тога доступни су стандардни прикази: листа објеката по класама, стабло позива (call tree) за сваки објекат и генератор извештаја. За разлику од Android Studio-а, Xcode не користи .hprof, већ чува податке у сопственом формату .trace, компатибилном са Instruments-ом.

swift
// Типично iOS цурење — retain cycle кроз затварање
class NetworkManager {
    var onComplete: ((Data) -> Void)?

    func startRequest() {
        // ❌ Затварање хвата self — retain cycle
        onComplete = { data in
            self.process(data)
        }
    }
    func process(_ data: Data) {}
}

Leaks instrument аутоматски детектује retain cycles и цурења анализом графа референци. Означава објекте који цуре љубичастом иконом и приказује пут до корена (GC root). За отклањање retain cycle-а довољно је додати [weak self] или [unowned self] у затварање. Редовно покретање Leaks instrument-а је обавезна фаза CI-а у тимовима који користе Swift за iOS развој.

swift
// Исправка — слаба референца на self
onComplete = { [weak self] data in
    guard let self else { return }
    self.process(data)
}

Shallow size, retained size и dominator tree

За коректну анализу heap dump-а потребно је разумети три кључне метрике. Shallow size — обим меморије коју директно заузима објекат: његова поља, заглавље (header) и поравнање. За типичан Java/Kotlin објекат shallow size износи 16–40 бајтова. Retained size — shallow size објекта плус укупан shallow size свих објеката који су доступни само кроз овај објекат (односно постаће смеће при његовом уклањању). Управо retained size показује стварни утицај објекта на потрошњу меморије.

МетрикаОписПример
Shallow sizeВеличина самог објекта у бајтовимаBitmap (100×100) = 40 016 B
Retained sizeShallow size + све што држиActivity са View Tree = 2–5 MB
Deep sizeRetained size + угнежђени објекти из других графоваScrollView са адаптером = 10–50 MB

Dominator tree — структура у којој сваки објекат упућује на свог „доминатора“ — објекат који контролише његову доступност. Ако се доминатор избрише, сви објекти његовог подстабла постају смеће. Анализа dominator tree-а је најбржи начин за проналажење објекта који држи највише меморије. Према Eclipse MAT-у (Memory Analyzer Tool), 90% цурења се открива прегледом top-20 dominator tree-а за 5 минута.

Анализа цурења меморије путем heap dump-а

Процес анализе цурења путем heap dump-а састоји се од неколико корака. Корак 1: извршите радњу која би требало да ослободи меморију (затворите екран, завршите операцију). Корак 2: позовите GC (System.gc() у Android-у, принудни snapshot у Xcode-у) и направите heap dump. Корак 3: пронађите објекте који су требали бити уништени (нпр. инстанца Activity након finish). Корак 4: за сумњиви објекат извршите Path to GC Roots — ланац референци који држи објекат живим. Последња референца у ланцу је узрок цурења.

Пут до GC Roots (Path to GC Roots)

Функција Path to GC Roots је доступна у Android Studio Profiler-у, Eclipse MAT-у и Xcode Instruments-у. Приказује најкраћи ланац референци од GC root-а до проблематичног објекта. Искључивањем слабих (weak) и меких (soft) референци добијате само јаке (strong) — оне које заиста спречавају сакупљање. Према статистици Square Engineering-а, 70% цурења у Android апликацијама изазвано је са само два обрасца: статичке референце на Activity или Context и регистровани али неодјављени listener-и.

kotlin
// Пример цурења кроз статичку референцу
object AppCache {
    private val cache = mutableMapOf<String, Any>()

    fun storeActivityReference(activity: Activity) {
        cache["current_activity"] = activity // ❌ Цурење!
    }
}

// Исправка: слаба референца
object AppCacheFixed {
    private val cache = mutableMapOf<String, WeakReference<Any>>()
}

Поређење два heap dump-а

Техника comparison mode — један од најефикаснијих метода за проналажење цурења. Направите heap dump пре и после понављајуће радње (нпр. пет прелазака на екран и назад). Упоредите број инстанци кључних класа: ако се број Activity повећао, иако су све активности затворене — то је цурење. Android Studio и Eclipse MAT подржавају аутоматско поређење дампова са истицањем разлика. Према Google-у, поређење дампова омогућава проналажење цурења невидљивих при једнократној анализи захваљујући акумулацији ефекта.

Практичне препоруке за смањење потрошње меморије

На основу анализе heap dump-ова у реалним пројектима развијене су проверене праксе оптимизације меморије. Користите WeakReference за кешеве, повратне позиве и референце на контекст у дугоживећим објектима. Одјављујте listener-е у onPause/onDestroy за Android и deinit за iOS. Избегавајте велике статичке колекције — ако су неопходне, користите LruCache са ограничењем величине. Оптимизујте Bitmap-ове: учитавајте слике са одговарајућим inSampleSize, користите Glide или Picasso са дисковним кешом.

Профилисање меморије у процесу развоја

Укључите редовно снимање heap dump-а у CI. Подесите задатак који покреће инструментиране UI тестове, извршава кључне корисничке сценарије и упоређује heap dump са baseline-ом. Ако retained size порасте за више од 5% у односу на baseline, изградња се означава као регресија. Овај приступ се практикује у Airbnb-у, Uber-у и другим компанијама са високим захтевима за квалитетом. Према Uber Engineering-у, увођење аутоматске анализе heap dump-а у CI смањило је број багова везаних за меморију за 70% у тромесечју.

groovy
// Пример Gradle задатка за аутоматски heap dump у CI-ју
task profileMemory(type: Exec) {
    commandLine 'adb', 'shell',
        'am start -n com.example/.MainActivity'
    // Чекање учитавања
    doLast {
        exec { commandLine 'adb', 'shell',
            'am broadcast -a com.example.DUMP_HEAP' }
    }
}

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

Која је разлика између shallow size и retained size?

Shallow size — величина самог објекта (поља + заглавље). Retained size — величина објекта плус свих објеката који ће постати смеће при његовом уклањању. Retained size је главни показатељ утицаја објекта на потрошњу меморије.

Како направити heap dump на физичком Android уређају?

Кроз Android Studio Profiler изаберите уређај и процес, кликните Dump Java Heap. Алтернативно — преко командне линије: adb shell am dumpheap PID /sdcard/dump.hprof, затим adb pull.

Зашто heap dump може бити огроман (500 MB+)?

Heap dump укључује све живе објекте. Ако апликација користи кешеве, Bitmap-ове или обрађује велике податке, дамп може достићи стотине мегабајта. Филтрирајте по класама или користите Eclipse MAT за учитавање само индекса.

Може ли се heap dump анализирати без Android Studio-а?

Да, користите Eclipse MAT (Memory Analyzer Tool) — бесплатан алат за анализу .hprof датотека. Подржава dominator tree, path to GC roots, поређење дампова и аутоматско проналажење цурења путем Leak Suspects Report-а.

Да ли heap dump смањује перформансе апликације?

Сам дамп — да, јер прикупљање дампа зауставља све нити (stop-the-world). Без дампа — не. Правите дамп у контролисаним условима (тест окружење, CI), не на продукцији.

Резиме

  • Heap Dump — потпун снимак хеапа апликације са информацијама о сваком објекту и везама између њих.
  • Android Studio Memory Profiler и Xcode Instruments Allocations — основни алати за снимање дампова.
  • Shallow size — величина самог објекта; retained size — величина објекта са целим подграфом зависности.
  • Dominator tree — стабло доминатора које приказује објекте који контролишу највише меморије.
  • Path to GC Roots — ланац јаких референци који спречава сакупљање објекта од стране garbage collector-а.
  • Поређење два heap dump-а (пре/после радње) — најпоузданији метод откривања цурења.
  • Аутоматизација снимања и анализе heap dump-ова у CI-ју спречава регресије меморије у фази развоја.

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

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

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

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