OutOfMemoryError — Java Virtual Machine (JVM) və ya Android Runtime (ART) yeni obyekt üçün yığında (Heap) yer olmadığına görə yaddaş ayıra bilmədikdə meydana çıxan ölümcül istisnadır. Square Engineering-ə görə, mobil tətbiqlərdə OutOfMemoryError-ların 70%-i yaddaş sızmaları səbəbindən baş verir, limitin həqiqi aşılmasından deyil. OOM səbəblərini anlamaq tətbiqin sabit işləməsinin açarıdır.
Əsas məqamlar
OutOfMemoryError (OOM) — Java/Kotlin-də VirtualMachineError ailəsindən olan və yeni obyekt üçün yaddaş ayırmanın mümkünsüzlüyünü bildirən istisnadır. Yoxlanılan istisnalardan fərqli olaraq, OOM Error-dır və catch vasitəsilə işlənmə tələb etmir — texniki olaraq tutmaq mümkün olsa da. OOM baş verdikdən sonra tətbiq adətən qeyri-sabit vəziyyətdə olur və onu bağlamaq tövsiyə olunur.
Android-də hər tətbiqin istehsalçı tərəfindən təyin edilmiş Heap limiti var. 6+ GB RAM-lı müasir smartfonlar üçün limit 256–512 MB, büdcə cihazları üçün — 128–192 MB təşkil edir. Bütün canlı obyektlərin ümumi həcmi bu limiti keçdikdə, ART OutOfMemoryError atır.
Vacibdir anlamaq: OOM həmişə cihazda fiziki yaddaşın bitdiyi demək deyil. Bu, tətbiqin sistem tərəfindən təyin edilmiş Heap limitini tükətdiyi deməkdir. Digər tətbiqlərin boş yaddaşı ola bilər, lakin Android-də proses izolyasiyası səbəbindən sizin tətbiqiniz ondan istifadə edə bilməz.
Beş ssenari mobil tətbiqlərdə müntəzəm olaraq OOM-a gətirib çıxarır. Hər ssenari müəyyən məlumat növü və ya əməliyyatla bağlıdır.
Bitmap — Android tətbiqlərində yaddaşın əsas istehlakçısıdır. FullHD şəklin (1920 × 1080) orijinal ölçüdə yüklənməsi ARGB_8888 formatında 8.3 MB yer tutur. RecyclerView-də 50 belə şəkil varsa — bu 415 MB-dır və istənilən cihazın Heap-ni aşır. Şəkillərin inSampleSize olmadan yüklənməsi — zəif cihazlarda zəmanətli OOM-dur.
Avtomatik miqyaslama üçün Glide və ya Coil istifadə edin. Bu kitabxanalar şəkilləri orijinal rezolyusiyaya deyil, View-ə uyğun ölçüdə yükləyir. Birbaşa BitmapFactory.Options istifadəsi üçün inSampleSize tətbiq edin: onu ikinin qüvvəti olaraq hesablayın ki, son ölçü 2048 × 2048 pikseli keçməsin. Şəffaflığı olmayan şəkillər üçün ARGB_8888 əvəzinə RGB_565 istifadə edin — bu yaddaş istehlakını iki dəfə azaldır.
fun loadScaledBitmap(path: String, reqWidth: Int): Bitmap? {
val opts = BitmapFactory.Options().apply {
inJustDecodeBounds = true
}
BitmapFactory.decodeFile(path, opts)
opts.inSampleSize = calculateSampleSize(opts.outWidth, reqWidth)
opts.inJustDecodeBounds = false
return BitmapFactory.decodeFile(path, opts)
}
Bir neçə KB-lıq sızma OOM-a səbəb olmaz. Lakin hər ekranda onlarla sızma yığılır: hər ekrana keçid sızma əlavə edir, GC obyektləri boşalda bilmir, Heap dolur. Tipik nümunə: istifadəçi profil ekranını 20 dəfə açıb bağlayır → Heap 200 MB artır → tətbiq OOM ilə çökür.
Avtomatik sızma aşkarlanması üçün layihəyə LeakCanary quraşdırın. O, dəqiq stack trace ilə hər sızan obyekti göstərəcək. Bütün sızmalar düzəldildikdən sonra Heap istehlakı sabit olacaq: ekran bağlandıqdan sonra yaddaş baza səviyyəsinə qayıdır.
Faylların tamamilə byte[]-ə yüklənməsi — OOM-a birbaşa yoldur. 50 MB-lıq JSON faylı parsings zamanı eyni ölçüdə string üstəgəl DOM modeli yaradacaq. Yaddaşa yüklənmiş video fayllar, audio buferlər və böyük protobuf məlumat dəstləri — hamısı bir əməliyyatda Heap limitini keçə bilər.
Böyük məlumatları axınlarla emal edin: 4–8 KB buferli InputStream, Streaming JSON-parser (Jackson və ya Gson JsonReader ilə), video üçün MediaCodec. Heç vaxt mövcud Heap-in 10%-dən böyük fayllarda File.readBytes() çağırmayın.
Dövrədə intensiv obyekt yaratma, aralıq GC olmadan, xüsusilə kiçik Heap-li cihazlarda OOM-a gətirib çıxara bilər. Nümunə: for dövrəsində GC-nin toplamağa vaxtı olmayan 100 000 obyektin yaradılması. Bu, oyunlarda və qrafik redaktorlarda daha çox rast gəlinir.
Kütləvi şəkildə yaradılıb məhv edilən obyektlər üçün Object Pool istifadə edin. Rəqəmsal məlumatlar üçün primitiv tiplərdən istifadə edin (List<Float> əvəzinə FloatArray). ViewHolder Pool ilə RecyclerView bu problemi UI komponentləri üçün həll edir.
Fragmentasiya — ümumi boş yaddaşın kifayət etdiyi, lakin yeni obyekt üçün fasiləsiz blokun olmadığı haldır. ART GC zamanı Heap-i kompaktlaşdırır, lakin həmişə uğurla deyil. Böyük massivlər (Bitmap, byte[]) fragmentasiyaya ən həssas olanlardır.
Android 8+-da ART gənc və yaşlı obyektləri ayırmaqla fragmentasiyanı azaldan Generational GC istifadə edir. Buna baxmayaraq, bir hovuzda müxtəlif ölçülü fraqmentlər ayırmaqdan çəkinin — sabit ölçülü pre-allocated buferlərdən istifadə etməyə çalışın.
Heap limiti Android-də sabit deyil — istehsalçıdan, cihaz modelindən və OS versiyasından asılıdır. Google Compatibility Definition Document (CDD) vasitəsilə minimum tələbləri müəyyən edir, lakin istehsalçılar faktiki dəyərləri təyin edir.
| Cihaz kateqoriyası | Tipik Heap | largeHeap |
|---|---|---|
| Büdcə (1–2 GB RAM) | 128–192 MB | 256–384 MB |
| Orta (3–4 GB RAM) | 256–384 MB | 512 MB |
| Flaqman (6+ GB RAM) | 384–512 MB | 768 MB–1 GB |
| Planşetlər (4+ GB RAM) | 256–512 MB | 768 MB |
| Wear OS | 32–64 MB | Yoxdur |
Artırılmış limiti manifestdə android:largeHeap="true" vasitəsilə tələb etmək olar. Ehtiyatla istifadə edin: Heap-i artırmaq sızma problemini həll etmir və sistem digər tətbiqləri öldürməyə məcbur olarsa, istifadəçi təcrübəsini pisləşdirə bilər. Wear OS üçün Heap limiti minimaldır — cəmi 32–64 MB, burada largeHeap mövcud deyil və yaddaş qənaəti ikiqat vacibdir.
OOM diaqnostikası Heap Dump analizi və hansı obyektlərin yaddaş istehlak etdiyini anlamağı tələb edir. Android Studio bütün lazımi alətləri təmin edir.
Addım 1: OOM anını yaxalayın. Android Memory Profiler-də Record memory allocations düyməsini basın və çökməyə səbəb olan ssenarini icra edin. Profiler OOM-dan əvvəl alokasiya sıçrayışını göstərəcək. OOM təkrarlanmırsa, debug-build-də android:smallHeap vasitəsilə Heap-i azaldın və ya əl ilə GC çağırışı ilə DDMS istifadə edin.
Addım 2: Pik yük anında (OOM-dan əvvəl) Heap Dump çıxarın. Dump-ı Android Studio-da açın: Classes sekmesi Retained Size-a görə sıralanmışdır. Ən böyük obyektlər — Bitmap, byte[], String. Hər Bitmap üçün ölçüyü (width × height × 4 bayt) və Stack Trace vasitəsilə yükləmə yolunu yoxlayın.
Addım 3: Təkrarlanan obyektlərin sayını analiz edin. 200 eyni Fragment və ya Activity görürsünüzsə — bu sızmadır. Eyni ölçülü 500 Bitmap varsa — şəkil keşləmə problemi. MAT (Memory Analyzer Tool) Heap-in 80%-ni saxlayan obyektləri göstərən Dominator Tree ilə daha dərin analiz təmin edir.
// Heap Dump üçün əmr adb vasitəsilə
adb shell am dumpheap com.example.app /data/local/tmp/dump.hprof
adb pull /data/local/tmp/dump.hprof.
Kompleks OOM qarşısının alınması strategiyası beş qoruma səviyyəsini əhatə edir: memarlıq həllərindən prodakşn monitorinqinə qədər.
ViewModel + Repository nümunəsi məlumatları UI-dən ayırır və ekran döndərmə zamanı View-in saxlanmasının qarşısını alır. ViewModel Activity-dən uzun yaşayır, onun məlumatları itmir və View yaddaşda məlumatların təkrarlanmadan yenidən yaradıla bilər. Vəziyyətləri idarə etmək üçün LiveData əvəzinə StateFlow istifadə edin.
Glide — şəkillərlə iş üçün məcburi kitabxanadır. Avtomatik miqyaslayır, keşləyir (disk + yaddaş) və Bitmap-i recycl edir. Böyük siyahılar üçün diskCacheStrategy və skipMemoryCache konfiqurasiya edin. Animasiyalı şəkillər üçün Glide-i GIF/WebP ilə istifadə edin — onlar Bitmap ardıcıllığından daha az yaddaş tutur.
Firebase Performance Monitoring yaddaş istehlakını real vaxtda izləyir. Heap-in limitin 80%-dən çox olmasına alert qoyun — bu yoxlama siqnalıdır. Crashlytics OOM-u istisna kimi toplayır və çökmədən əvvəl son Heap vəziyyətini göstərir. Android 11+ üçün OOM-qapanmalarını aşkarlamaq üçün ApplicationExitInfo istifadə edin.
Məcburi olaraq tətbiqi minimal Heap (128–192 MB) olan cihazlarda sınaqdan keçirin. Kiçik ekranlı və kiçik Heap-li emulator büdcə cihazını simulyasiya edir. Tətbiq belə bir cihazda işləyirsə, flaqmanlarda OOM problemi olmayacaq. Müxtəlif qiymət kateqoriyalarından real cihazlarla Firebase Test Lab istifadə edin.
// Ağır əməliyyatdan əvvəl mövcud Heap-in yoxlanılması
fun canAllocate(requiredBytes: Long): Boolean {
val runtime = Runtime.getRuntime()
val free = runtime.freeMemory()
return free > requiredBytes * 2 // 50% ehtiyat
}
Tez-tez verilən suallar
Texniki olaraq bəli, lakin bunu etmək tövsiyə edilmir. OOM-dan sonra tətbiq qeyri-sabit vəziyyətdə olur: yeni alokasiyalar işləməyə bilər, bəzi obyektlər qismən yaradılmış ola bilər. Catch-də yeganə ağıllı hərəkət — loglama və Activity-ni yenidən başlatmaqdır.
Heap limiti müxtəlif cihazlarda fərqlidir. 300 MB tələb edən əməliyyat limiti 192 MB olan cihazda çökəcək, lakin 512 MB olan flaqmanda işləyəcək. OOM ssenarilərini aşkarlamaq üçün minimal xüsusiyyətlərə malik cihazlarda sınaq keçirin.
largeHeap limiti artırır, lakin tətbiqi sürətləndirmir. GC fasilələri daha uzun olur, çünki böyük Heap-i yığmaq daha çox vaxt aparır. Sistem yaddaşı təmin etmək üçün fon tətbiqlərini öldürə bilər. largeHeap-i yalnız obyektiv olaraq çox yaddaşa ehtiyacı olan tətbiqlər üçün istifadə edin (kameralar, redaktorlar).
OOM — Heap çatışmazlığı zamanı tətbiq daxilində istisna. Sistem tərəfindən öldürmə (Low Memory Killer) — digər tətbiqlər üçün yaddaşı boşaltmaq məqsədilə Linux nüvəsinin prosesi öldürmə qərarıdır. Sistem tərəfindən öldürmədə tətbiq istisna almır — proses sadəcə sonlanır.
Düstur: width × height × bytesPerPixel. ARGB_8888 = 4 B/piksel, RGB_565 = 2 B/piksel. ARGB_8888-də FullHD Bitmap (1920 × 1080) = 8.3 MB. 4K Bitmap (3840 × 2160) = 33 MB. Şəkilləri həmişə ekranda göstərmək üçün lazım olan ölçüyə miqyaslayın.
Nəticə
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