LeakCanary — Square şirkəti tərəfindən Android tətbiqlərində yaddaş sızmalarının avtomatik aşkarlanması üçün açıq mənbəli kitabxanadır. O, inkişaf prosesinə inteqrasiya olunur və real vaxtda Activity, Fragment, ViewModel və digər komponentlərin həyat dövrünü izləyir, sızmalar baş verdikdən dərhal sonra xəbərdarlıq edir. Square Open Source məlumatlarına görə, kitabxana minlərlə layihədə istifadə olunur və Android-də yaddaş diaqnostikası üçün de-fakto standart hesab olunur.
Əsas qeydlər
LeakCanary — Square şirkəti tərəfindən hazırlanmış Android tətbiqlərində yaddaş sızmalarının avtomatik aşkarlanması üçün kitabxanadır. O, tətbiqin qurulma prosesinə inteqrasiya olunur və məhv edilməli olan obyektlərin (Activity, Fragment, View) yaddaşda qalıb-qalmadığını avtomatik izləyir. Sızma aşkarlandıqda LeakCanary heap dump yaradır və obyekti saxlayan istinad zəncirini analiz edir.
Kitabxana Android icmasında standarta çevrilib: GitHub məlumatlarına görə, layihə 28 mindən çox ulduz toplayıb və Google, Uber, Airbnb və Facebook tətbiqlərində istifadə olunur. LeakCanary iki əsas versiyada mövcuddur: klassik 1.x (əl ilə konfiqurasiya) və müasir 2.x (ContentProvider vasitəsilə avtomatik inteqrasiya). 2.x versiyası Application sinfində dəyişiklik tələb etmir — tam işləmək üçün bir asılılıq kifayətdir.
LeakCanary-nin əsas vəzifəsi, obyektin həyat dövrü başa çatdıqdan sonra yaddaşda mövcud olmağa davam etdiyi vəziyyəti aşkar etməkdir. Bu, statik sahələr, sinqletonlar, qeydiyyatdan keçirilməmiş callback-lər, anonim siniflər və xarici obyektləri ələ keçirən domklyuzyalar vasitəsilə sızmalar üçün xarakterikdir.
Android-də yaddaş sızmaları mobil cihazlarda məhdud RAM həcminə görə desktop-dan daha kritikdir. Hər ekran dəyişikliyində cəmi 5–10 MB sızma belə tətbiqdən 30–40 dəqiqə istifadədən sonra OutOfMemoryError-a səbəb ola bilər. LeakCanary bu cür problemləri inkişaf mərhələsində aşkar edir, prodakşnda gözləmədən.
LeakCanary məcburi zibil yığıcı çağırışı ilə birlikdə zəif istinadlardan (WeakReference) istifadə edir. Activity və ya Fragment onDestroy çağırdıqda, LeakCanary bu obyektə WeakReference yaradır və qısa gecikmədən sonra (standart 5 saniyə) GC-ni işə salır. Əgər GC-dən sonra obyekt WeakReference vasitəsilə hələ də əlçatandırsa, bu, onun güclü istinadla saxlanıldığı anlamına gəlir — sızma qeydə alınır.
Sızma aşkarlandıqdan sonra LeakCanary heap dump (yığın görüntüsü) edir — HPROF formatında tətbiq yaddaşının tam şəkili. Sonra daxili analizator (2.x versiyası üçün Shark) GC Roots-dən sızan obyektə qədər əlçatanlıq qrafiki qurur və ən qısa yolu — obyekti yaddaşda saxlayan istinad zəncirini tapır.
// LeakCanary aşkarlama məntiqinin sadələşdirilmiş versiyası
class ObjectWatcher {
private val watchedReferences = CopyOnWriteArrayList<KeyedWeakReference>()
fun watch(watchedObject: Any, description: String) {
val reference = KeyedWeakReference(watchedObject, description)
watchedReferences.add(reference)
BackgroundHandler.postDelayed({
checkForLeaks()
}, 5000)
}
private fun checkForLeaks() {
GcTrigger.runGc() // məcburi GC
for (ref in watchedReferences) {
if (ref.get() != null) {
onLeakFound(ref) // obyekt GC-dən sağ çıxdı — bu sızmadır
}
}
}
}
Əsas məqam — məcburi GcTrigger.runGc() çağırışıdır. Onsuz, həqiqətən sızmış obyekti GC-nin hələ toplamağa vaxtı olmayan obyektdən ayırmaq mümkün deyil. LeakCanary bunu üç dəfə edir: üç GC dövründən sonra obyekt hələ də yaddaşdadırsa — sızma təsdiqlənir.
Shark — Kotlin dilində yazılmış LeakCanary 2.x-ə daxil olan heap dump analizatorudur. Əvvəlki HAHA analizatorundan fərqli olaraq, Shark bütün HPROF faylını yaddaşa yükləmir, əvəzində minimal ayırmalarla obyekt qrafikini gəzir. Bu, analiz zamanı RAM istehlakını 50 MB-dan 2–5 MB-a endirir və analiz vaxtını 30 saniyədən 1–3 saniyəyə qədər azaldır.
Müasir Android layihəsində LeakCanary 2.x quraşdırılması build.gradle-da bir sətir çəkir. Kitabxana avtomatik başlatma üçün ContentProvider istifadə edir — Application sinfini dəyişdirmək və ya MainActivity-ə kod əlavə etmək lazım deyil. Qoşulma yalnız debug-build üçün edilir ki, release APK-da artıq kod olmasın.
// build.gradle (app/module)
dependencies {
// debugImplementation — kitabxana yalnız debug-build üçün
debugImplementation "com.squareup.leakcanary:leakcanary-android:2.14"
}
Asılılıq əlavə edildikdən və layihə yenidən qurulduqdan sonra LeakCanary avtomatik olaraq tətbiqdə görünür. İlk işə salmada kitabxana aktivləşdirmə barədə sistem bildirişi göstərir. Bütün aşkar edilmiş sızmalar bildirişlər şəklində göstərilir — bildirişə klikləmək ətraflı hesabat (LeakTrace) olan ekranı açır.
Fərdiləşdirmə üçün öz AppWatcherInstaller-inizi yarada və parametrləri dəyişə bilərsiniz: GC gözləmə müddəti, izlənən obyekt növlərinin siyahısı, heap dump-ın diskə yazılmasını aktivləşdirmək. Lakin layihələrin 90%-i üçün standart konfiqurasiya optimaldır.
2.12 versiyasından başlayaraq, LeakCanary ViewModel, korutin skopları və Compose State obyektlərinin avtomatik izlənməsini dəstəkləyir. Əlavə asılılıqlar tələb olunmur — kitabxana layihədə hansı Jetpack komponentlərinin istifadə edildiyini özü müəyyən edir və müvafiq detektorları aktivləşdirir.
LeakCanary hesabatı (LeakTrace) — GC Root-dan sızan obyektə qədər çoxsətirli istinad zənciridir. Hər sətir sinif və sahəni göstərir, onun vasitəsilə güclü istinad keçir. Proqramçı zənciri aşağıdan yuxarıya oxumalıdır: alt sətir — sızan obyekt, üst sətir — giriş nöqtəsi (GC Root).
Adi LeakTrace belə görünür: GC Root → statik Application sahəsi → sinqleton → callback → Activity. Əgər proqramçı belə bir zəncir görürsə, problem aydındır: sinqleton Activity-yə istinadı ələ keçirmiş callbacki saxlayır. Həll yolu — sinqletonda güclü istinadı zəiflə əvəz etmək.
┬
├─ android.app.Application
│ Leaking: NO (Application — singleton)
│ ↓ Application.leakedActivities
├─ java.util.ArrayList
│ Leaking: NO (ArrayList — normal)
│ ↓ ArrayList[0]
├─ com.example.MainActivity
│ Leaking: YES (Activity destroyed but still in memory)
│ ↓ MainActivity.mCallback
├─ com.example.CallbackWrapper
│ Leaking: UNKNOWN
│ ↓ CallbackWrapper.mListener
│ ~~~~~~~~~~
├─ com.example.MyCallback (anonymous)
│ Leaking: UNKNOWN
│ ↓ MyCallback.this$0
├─ com.example.MainActivity
│ Leaking: YES (MainActivity is the leak)
╰
Bu nümunədə LeakCanary göstərir ki, MainActivity zəncir vasitəsilə saxlanılır: Application → ArrayList → MainActivity → CallbackWrapper → MyCallback → yenə MainActivity. this$0 oxu göstərir ki, anonim MyCallback sinfi Activity-yə xarici istinadı ələ keçirib. Həll yolu — callbacki zəif istinad etmək və ya onDestroy-də ləğv etmək.
LeakCanary həmçinin zəncirin hər bir elementi üçün sızma statusu göstərir: NO (sızma yoxdur — bu kök elementdir), YES (obyekt məhv edilməlidir), UNKNOWN (statusu müəyyən etmək mümkün olmadı). UNKNOWN statusu problem demək deyil — bu, LeakCanary-nin birmənalı təsnif edə bilmədiyi aralıq obyektdir.
1.x versiyasından 2.x-ə keçid köklü idi: tərtibatçılar kitabxananı sıfırdan yazdılar, köhnəlmiş HAHA analizatorunu Kotlin dilində yazılmış öz Shark mühərriki ilə əvəz edərək. Shark daha sürətli işləyir, analiz üçün daha az yaddaş tələb edir və sızmaların kök səbəblərini daha dəqiq müəyyən edir.
| Parametr | LeakCanary 1.x | LeakCanary 2.x |
|---|---|---|
| Analizatorun dili | Java (HAHA — Android SDK fork-u) | Kotlin (Shark — öz mühərrik) |
| Quraşdırma | Application-da AppWatcher-in əl ilə konfiqurasiyası | ContentProvider vasitəsilə avtomatik |
| Sürət | Heap dump analizi üçün 10–30 saniyə | Heap dump analizi üçün 1–5 saniyə |
| Performans | Analiz zamanı 10–50 MB RAM | Analiz zamanı 2–10 MB RAM |
Shark-ın əsas üstünlüyü — bütün heap dump-ı yaddaşa yükləmir, əvəzində minimal ayırmalarla onun istinad qrafikini gəzir. Bu, LeakCanary 2.x-i analiz zamanı OutOfMemoryError riski olmadan aşağı RAM həcmli cihazlarda istifadəyə yararlı edir.
2.x versiyasında həmçinin Android Studio Memory Profiler-də sonrakı analiz üçün heap dump-ın fayla ixracı imkanı yaranıb. Bunun üçün AppWatcher konfiqurasiyasında dumpHeapWhenLeakFound parametrini aktivləşdirmək lazımdır.
LeakCanary Android üçün xarakterik olan bir neçə sinif sızmanı effektiv şəkildə aşkar edir. Ən çox Activity-yə statik istinadlar vasitəsilə sızma baş verir — tərtibatçılar Activity kontekstinə istinadı sinqletonda saxlayır və Activity həyat dövrü başa çatdıqdan sonra GC tərəfindən toplana bilmir.
Tezlik baxımından ikinci kateqoriya — qeydiyyatdan keçirilməmiş dinləyicilər vasitəsilə sızmalardır. Əgər onStart-da registerListener çağırılıbsa, lakin onStop/onDestroy-də unregisterListener çağırılmayıbsa — dinləyici obyekti aktivlik məhv edildikdən sonra belə sistem tərəfindən saxlanılır. LeakCanary hansı dinləyicinin və hansı sistem xidmətində aktiv qaldığını birmənalı göstərir.
// Tipik sızma: Activity sinqleton callback-də ələ keçirilib
object AnalyticsManager {
private var callback: ((String) -> Unit)? = null
fun register(callback: (String) -> Unit) {
this.callback = callback // callback-ə güclü istinad
}
fun unregister() {
callback = null // onDestroy-də ÇAĞIRMAĞI UNUTMA!
}
}
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
AnalyticsManager.register { event ->
logEvent(event) // lambda this-i ələ keçirir
}
// onDestroy-də unregister çağırılmasa → Activity sızması
}
}
Üçüncü kateqoriya — BackStack-də Fragment vasitəsilə sızmalardır. Əgər FragmentTransaction.addToBackStack() geri qayıdarkən Fragment silinmədən çağırılırsa, köhnə Fragment nümunələri yaddaşda qalır. LeakCanary inkişafın erkən mərhələlərində belə gizli sızmaları aşkar etməyə kömək edir.
Hər aşkar edilmiş sızma üçün LeakCanary təsvir və düzəliş tövsiyələri təklif edir. 2.14 versiyasında Android Lint ilə inteqrasiya əlavə edilib — kitabxana CI-də sızma aşkarlandıqda issue tracker-də avtomatik tapşırıqlar yarada bilər.
Tez-tez verilən suallar
Bəli, mütləq. LeakCanary build.gradle-da debugImplementation vasitəsilə qoşulur, bu da onu avtomatik olaraq release qurulmasından çıxarır. Əgər implementation vasitəsilə qoşsanız, kitabxana release APK-ya düşəcək və son istifadəçilərə sızmaları göstərəcək — bu yolverilməzdir.
Performansa təsir minimaldır. LeakCanary yalnız komponentin onDestroy-dən sonra aktivləşir və UI-nin render edilməsinə və ya toxunuşların işlənməsinə müdaxilə etmir. Yeganə xərc — məcburi GC-nin qısa fasiləsi (təxminən 100 ms) və sızma zamanı heap dump yazısı (saniyənin yüzdə biri).
LeakCanary avtomatik olaraq HPROF formatında heap dump-ı tətbiq qovluğunda saxlayır. Faylı Android Studio vasitəsilə ixrac etmək olar: Device File Explorer → data/data/com.example/files/leakcanary/. Göstərmək üçün faylı Memory Profiler-də Capture → Open Heap Dump vasitəsilə açın.
Bəli, 2.12 versiyasından başlayaraq LeakCanary Jetpack Compose-u tam dəstəkləyir. Kitabxana Composition kontekstlərini və State obyektlərini izləyir, Composable funksiyalarında sızmaları avtomatik aşkar edir. Ayrıca konfiqurasiya tələb olunmur — qutudan çıxan kimi işləyir.
Yalançı aktivləşmələr mümkündür, lakin nadirdir. LeakCanary sızma elan etməzdən əvvəl üçqat GC çağırışından istifadə edir, bu da yalançı pozitivlərin çoxunu aradan qaldırır. Əgər aktivləşmənin yalançı olduğunu düşünürsünüzsə — konfiqurasiyada konkret sinif üçün IgnoredReference yaradın.
Xülasə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun