OutOfMemoryError ایک مہلک استثناء ہے جو اس وقت ہوتا ہے جب Java Virtual Machine (JVM) یا Android Runtime (ART) Heap میں جگہ کی کمی کی وجہ سے کسی نئی شے کے لیے میموری مختص نہیں کر سکتا۔ Square Engineering کے مطابق، موبائل ایپلیکیشنز میں 70% OutOfMemoryError میموری لیک کی وجہ سے ہوتے ہیں، نہ کہ حقیقی حد سے تجاوز کرنے کی وجہ سے۔ OOM کی وجوہات کو سمجھنا ایپلیکیشن کے استحکام کی کلید ہے۔
اہم نکات
OutOfMemoryError (OOM) Java/Kotlin میں VirtualMachineError خاندان کا ایک استثناء ہے جو نئی شے کے لیے میموری مختص کرنے میں ناکامی کا اشارہ دیتا ہے۔ چیک کیے گئے استثناء کے برعکس، OOM ایک Error ہے اور اسے catch کے ذریعے سنبھالنے کی ضرورت نہیں ہے — اگرچہ اسے تکنیکی طور پر پکڑا جا سکتا ہے۔ OOM ہونے کے بعد، ایپلیکیشن عام طور پر غیر مستحکم حالت میں ہوتی ہے اور اسے ختم کرنے کی سفارش کی جاتی ہے۔
Android پر، ہر ایپلیکیشن کی ایک Heap حد ہوتی ہے جو ڈیوائس بنانے والے کے ذریعے مقرر کی جاتی ہے۔ 6+ GB RAM والے جدید اسمارٹ فونز کے لیے، حد 256–512 MB ہے، بجٹ ڈیوائسز کے لیے — 128–192 MB۔ جب تمام زندہ اشیاء کا کل حجم اس حد سے تجاوز کر جاتا ہے، تو ART OutOfMemoryError پھینکتا ہے۔
یہ سمجھنا ضروری ہے: OOM کا ہمیشہ یہ مطلب نہیں ہے کہ ڈیوائس کی فزیکل میموری ختم ہو گئی ہے۔ اس کا مطلب ہے کہ ایپلیکیشن نے سسٹم کے ذریعے مقرر کردہ اپنی Heap حد ختم کر دی ہے۔ دوسری ایپلیکیشنز کے پاس خالی میموری ہو سکتی ہے، لیکن Android میں پروسیس علیحدگی کی وجہ سے آپ کی ایپلیکیشن اسے استعمال نہیں کر سکتی۔
پانچ منظرنامے باقاعدگی سے موبائل ایپلیکیشنز میں OOM کا سبب بنتے ہیں۔ ہر منظر نامہ ایک مخصوص ڈیٹا کی قسم یا آپریشن سے منسلک ہے۔
Bitmap Android ایپلیکیشنز میں میموری کا سب سے بڑا صارف ہے۔ FullHD تصویر (1920 × 1080) کو اصل سائز میں لوڈ کرنے پر ARGB_8888 فارمیٹ میں 8.3 MB لگتا ہے۔ اگر RecyclerView میں ایسی 50 تصویریں ہوں — تو یہ 415 MB ہے، جو کسی بھی ڈیوائس کے Heap سے زیادہ ہے۔ inSampleSize کے بغیر تصویریں لوڈ کرنا کمزور ڈیوائسز پر یقینی OOM ہے۔
خودکار پیمائش کے لیے Glide یا Coil استعمال کریں۔ یہ لائبریریاں تصاویر کو اصل ریزولوشن کے بجائے View کے مطابق سائز میں لوڈ کرتی ہیں۔ BitmapFactory.Options کے براہ راست استعمال کے لیے inSampleSize لگائیں: اسے دو کی قوت کے طور پر شمار کریں تاکہ حتمی سائز 2048 × 2048 پکسلز سے زیادہ نہ ہو۔ اضافی طور پر، شفافیت کے بغیر تصاویر کے لیے ARGB_8888 کی بجائے RGB_565 استعمال کریں — اس سے میموری کی کھپت آدھی رہ جاتی ہے۔
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)
}
ایک چند KB کا لیک OOM کا سبب نہیں بنے گا۔ لیکن ہر اسکرین پر درجنوں لیک جمع ہوتے ہیں: ہر اسکرین ٹرانزیشن ایک لیک کا اضافہ کرتی ہے، GC اشیاء کو آزاد نہیں کر سکتا، اور Heap بھر جاتا ہے۔ ایک عام نمونہ: صارف پروفائل اسکرین کو 20 بار کھولتا اور بند کرتا ہے → Heap 200 MB بڑھتا ہے → ایپلیکیشن OOM کے ساتھ کریش ہوتی ہے۔
خودکار لیک کا پتہ لگانے کے لیے پروجیکٹ میں LeakCanary انسٹال کریں۔ یہ عین مطابق اسٹیک ٹریس کے ساتھ ہر لیک شدہ شے دکھائے گا۔ تمام لیک ٹھیک کرنے کے بعد، Heap کی کھپت مستحکم ہو جاتی ہے: اسکرین بند کرنے کے بعد، میموری بیس لیول پر واپس آ جاتی ہے۔
پوری فائلوں کو byte[] میں لوڈ کرنا OOM کا براہ راست راستہ ہے۔ 50 MB کی JSON فائل پارس کرنے کے دوران ایک ہی سائز کا سٹرنگ اور ایک DOM ماڈل بنائے گی۔ میموری میں لوڈ کردہ ویڈیو فائلیں، آڈیو بفرز، اور بڑے protobuf ڈیٹاسیٹ — یہ سب ایک آپریشن میں Heap کی حد سے تجاوز کر سکتے ہیں۔
بڑے ڈیٹا کو سٹریمز کے ذریعے پروسیس کریں: 4–8 KB بفر کے ساتھ InputStream، سٹریمنگ JSON پارسر (Jackson یا JsonReader کے ساتھ Gson)، ویڈیو کے لیے MediaCodec۔ دستیاب Heap کے 10% سے زیادہ سائز والی فائلوں پر کبھی File.readBytes() کال نہ کریں۔
لوپ میں درمیانی GC کے بغیر اشیاء کی بہت زیادہ تخلیق OOM کا سبب بن سکتی ہے، خاص طور پر چھوٹے Heap والے ڈیوائسز پر۔ مثال: for-loop میں 100,000 اشیاء پیدا کرنا جو GC کے جمع کرنے سے پہلے Heap میں نہیں سماتیں۔ یہ گیمز اور گرافکس ایڈیٹرز میں زیادہ عام ہے۔
ان اشیاء کے لیے Object Pool استعمال کریں جو بڑی تعداد میں بنائی اور تباہ کی جاتی ہیں۔ عددی ڈیٹا کے لیے پریمیٹو استعمال کریں (List<Float> کی بجائے FloatArray)۔ ViewHolder Pool کے ساتھ RecyclerView UI اجزاء کے لیے اس مسئلے کو حل کرتا ہے۔
بکھراؤ ایک ایسی حالت ہے جہاں مجموعی طور پر کافی خالی میموری ہے، لیکن نئی شے کے لیے کوئی متصل بلاک نہیں ہے۔ ART GC کے دوران Heap کو سکیڑتا ہے، لیکن ہمیشہ کامیابی سے نہیں۔ بڑی اریاں (Bitmap, byte[]) بکھراؤ کے لیے سب سے زیادہ حساس ہوتی ہیں۔
Android 8+ پر ART Generational GC استعمال کرتا ہے، جو نوجوان اور پرانی اشیاء کو الگ کرکے بکھراؤ کو کم کرتا ہے۔ اس کے باوجود، ایک ہی پول میں مختلف سائز کے ٹکڑے مختص کرنے سے گریز کریں — پہلے سے مختص کردہ مقررہ سائز کے بفر استعمال کرنے کی کوشش کریں۔
Android میں Heap کی حد ایک مستقل نہیں ہے — یہ بنانے والے، ڈیوائس ماڈل اور OS ورژن پر منحصر ہے۔ Google مطابقت کی تعریف دستاویز (CDD) کے ذریعے کم از کم تقاضے طے کرتا ہے، لیکن بنانے والے حقیقی اقدار طے کرتے ہیں۔
| ڈیوائس کی قسم | عام Heap | largeHeap |
|---|---|---|
| بجٹ (1–2 GB RAM) | 128–192 MB | 256–384 MB |
| درمیانی (3–4 GB RAM) | 256–384 MB | 512 MB |
| فلیگ شپ (6+ GB RAM) | 384–512 MB | 768 MB–1 GB |
| ٹیبلٹس (4+ GB RAM) | 256–512 MB | 768 MB |
| Wear OS | 32–64 MB | دستیاب نہیں |
آپ مینی فیسٹ میں android:largeHeap="true" کے ذریعے بڑھی ہوئی حد کی درخواست کر سکتے ہیں۔ احتیاط سے استعمال کریں: Heap بڑھانے سے لیک کا مسئلہ حل نہیں ہوتا اور اگر سسٹم آپ کی ایپلیکیشن کے لیے میموری خالی کرنے کے لیے دوسری ایپلیکیشنز کو بند کرنے پر مجبور ہو تو صارف کے تجربے کو خراب کر سکتا ہے۔ Wear OS کے لیے، Heap کی حد کم سے کم ہے — صرف 32–64 MB، یہاں largeHeap دستیاب نہیں ہے، اور میموری کی بچت دوگنی اہم ہے۔
OOM کی تشخیص کے لیے Heap Dump کا تجزیہ اور یہ سمجھنا ضروری ہے کہ کون سی اشیاء میموری استعمال کر رہی ہیں۔ Android Studio تمام ضروری ٹولز فراہم کرتا ہے۔
مرحلہ 1: OOM کے لمحے کو کیپچر کریں۔ Android Memory Profiler میں، Record memory allocations پر کلک کریں اور وہ منظر نامہ چلائیں جو کریش کا سبب بنتا ہے۔ Profiler OOM سے پہلے مختص میں اضافہ دکھائے گا۔ اگر OOM دوبارہ قابل تولید نہیں ہے، تو ڈیبگ بلڈ میں android:smallHeap کے ذریعے Heap کم کریں یا دستی GC کال کے ساتھ DDMS استعمال کریں۔
مرحلہ 2: چوٹی کے بوجھ پر (OOM سے پہلے) Heap Dump لیں۔ Android Studio میں Dump کھولیں: Classes ٹیب Retained Size کے مطابق ترتیب دیا گیا ہے۔ سب سے بڑی اشیاء Bitmap, byte[], String ہیں۔ ہر Bitmap کے لیے، سائز (چوڑائی × اونچائی × 4 بائٹ) اور Stack Trace کے ذریعے لوڈ کا راستہ چیک کریں۔
مرحلہ 3: ڈپلیکیٹ اشیاء کی تعداد کا تجزیہ کریں۔ اگر آپ 200 ایک جیسے Fragment یا Activity دیکھتے ہیں — یہ ایک لیک ہے۔ اگر ایک ہی سائز کے 500 Bitmap — یہ تصویر کیشنگ کا مسئلہ ہے۔ MAT (Memory Analyzer Tool) Dominator Tree کے ساتھ گہرا تجزیہ فراہم کرتا ہے جو دکھاتا ہے کہ کون سی اشیاء 80% Heap رکھتی ہیں۔
// adb کے ذریعے Heap Dump کمانڈ
adb shell am dumpheap com.example.app /data/local/tmp/dump.hprof
adb pull /data/local/tmp/dump.hprof.
ایک جامع OOM سے بچاؤ کی حکمت عملی میں تحفظ کی پانچ سطحیں شامل ہیں: آرکیٹیکچرل فیصلوں سے لے کر پروڈکشن مانیٹرنگ تک۔
ViewModel + Repository پیٹرن ڈیٹا کو UI سے الگ کرتا ہے اور اسکرین گھومنے پر View کو برقرار رہنے سے روکتا ہے۔ ViewModel Activity سے زیادہ زندہ رہتا ہے، اس کا ڈیٹا ضائع نہیں ہوتا، اور View کو میموری میں ڈیٹا ڈپلیکیٹ کیے بغیر دوبارہ بنایا جا سکتا ہے۔ واضح حالت کے انتظام کے لیے LiveData کی بجائے StateFlow استعمال کریں۔
Glide تصاویر کے ساتھ کام کرنے کے لیے ایک لازمی لائبریری ہے۔ یہ خود بخود پیمائش، کیش (ڈسک + میموری) اور Bitmap کو ری سائیکل کرتی ہے۔ بڑی فہرستوں کے لیے diskCacheStrategy اور skipMemoryCache کنفیگر کریں۔ اینی میٹڈ تصاویر کے لیے، GIF/WebP کے ساتھ Glide استعمال کریں — یہ Bitmap کی ترتیب سے کم میموری لیتے ہیں۔
Firebase Performance Monitoring حقیقی وقت میں میموری کی کھپت کو ٹریک کرتا ہے۔ جب Heap کا استعمال حد کے 80% سے تجاوز کر جائے تو الرٹ سیٹ کریں — یہ جانچ کا اشارہ ہے۔ Crashlytics OOM کو ایک استثناء کے طور پر جمع کرتا ہے اور کریش سے پہلے آخری معلوم Heap حالت دکھاتا ہے۔ Android 11+ کے لیے، OOM کے خاتمے کا پتہ لگانے کے لیے ApplicationExitInfo استعمال کریں۔
یقینی بنائیں کہ آپ کم سے کم Heap (128–192 MB) والے ڈیوائسز پر ایپلیکیشن کی جانچ کرتے ہیں۔ چھوٹی اسکرین اور چھوٹے Heap والا ایمولیٹر بجٹ ڈیوائس کی نقل کرتا ہے۔ اگر ایپلیکیشن ایسے ڈیوائس پر کام کرتی ہے، تو فلیگ شپ پر OOM کے مسائل نہیں ہوں گے۔ مختلف قیمت کے زمروں کے اصلی ڈیوائسز کے ساتھ Firebase Test Lab استعمال کریں۔
// بھاری آپریشن سے پہلے دستیاب Heap کی جانچ
fun canAllocate(requiredBytes: Long): Boolean {
val runtime = Runtime.getRuntime()
val free = runtime.freeMemory()
return free > requiredBytes * 2 // 50% بفر
}
اکثر پوچھے گئے سوالات
تکنیکی طور پر ہاں، لیکن یہ تجویز نہیں کیا جاتا۔ OOM کے بعد، ایپلیکیشن غیر مستحکم حالت میں ہوتی ہے: نئی مختص ناکام ہو سکتی ہے، اور کچھ اشیاء جزوی طور پر بن سکتی ہیں۔ Catch میں واحد معقول کارروائی لاگنگ اور Activity کو دوبارہ شروع کرنا ہے۔
Heap کی حد ڈیوائسز کے درمیان مختلف ہوتی ہے۔ ایک آپریشن جسے 300 MB کی ضرورت ہے، وہ 192 MB حد والے ڈیوائس پر ناکام ہوگا لیکن 512 MB والے فلیگ شپ پر کامیاب ہوگا۔ OOM کے منظرناموں کا پتہ لگانے کے لیے کم سے کم خصوصیات والے ڈیوائسز پر جانچ کریں۔
largeHeap حد بڑھاتا ہے لیکن ایپلیکیشن کو تیز نہیں کرتا۔ GC کا وقفہ لمبا ہو جاتا ہے کیونکہ بڑے Heap کو جمع کرنے میں زیادہ وقت لگتا ہے۔ سسٹم میموری فراہم کرنے کے لیے پس منظر کی ایپلیکیشنز کو بند کر سکتا ہے۔ largeHeap صرف ان ایپلیکیشنز کے لیے استعمال کریں جنہیں معروضی طور پر بہت زیادہ میموری کی ضرورت ہے (کیمرے، ایڈیٹرز)۔
OOM Heap کی کمی پر ایپلیکیشن کے اندر ایک استثناء ہے۔ سسٹم کل (Low Memory Killer) دوسری ایپلیکیشنز کے لیے میموری خالی کرنے کے لیے کسی عمل کو ختم کرنے کا Linux کرنل کا فیصلہ ہے۔ سسٹم کل میں، ایپلیکیشن کو استثناء نہیں ملتا — عمل صرف ختم ہو جاتا ہے۔
فارمولا: چوڑائی × اونچائی × bytesPerPixel۔ ARGB_8888 = 4 B/پکسل، RGB_565 = 2 B/پکسل۔ ARGB_8888 میں FullHD Bitmap (1920 × 1080) = 8.3 MB۔ 4K Bitmap (3840 × 2160) = 33 MB۔ تصاویر کو ہمیشہ اسکرین پر ڈسپلے کے لیے درکار سائز میں اسکیل کریں۔
خلاصہ
ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے
IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں