موبائل ڈیولپمنٹ میں Stack Overflow — یہ کیا ہے، وجوہات اور روک تھام کے طریقے

مصنف: IT Sectr اشاعت: 2026-03-29 مطالعے کا وقت: 9 منٹ

Stack Overflow ایک کال اسٹیک اوورفلو خرابی (java.lang.StackOverflowError) ہے جو تھریڈ کی زیادہ سے زیادہ اسٹیک گہرائی سے تجاوز کرنے پر ہوتی ہے۔ Java Virtual Machine Specification کے مطابق، 64 بٹ سسٹمز کے لیے JVM میں عام اسٹیک گہرائی 1024 فریم ہے۔ بنیادی وجہ بنیادی شرط کے بغیر لامتناہی ریکرشن ہے۔

اہم نکات

  • StackOverflowError — کال اسٹیک گہرائی کی حد سے تجاوز کرنے پر JVM خرابی
  • اسٹیک گہرائی ترتیب کے مطابق 512–2048 فریم تک محدود ہے
  • لامتناہی ریکرشن StackOverflowError کی سب سے عام وجہ ہے
  • دمی ریکرشن فنکشنل زبانوں کے برعکس، JVM میں بہتر نہیں کی جاتی
  • تکراری تبدیلی اوورفلو کو روکنے کا ایک قابل اعتماد طریقہ ہے

Stack Overflow کیا ہے

StackOverflowError جاوا ورچوئل مشین (JVM) یا Android Runtime (ART) کی ایک مہلک خرابی ہے جو اس وقت ہوتی ہے جب کسی تھریڈ کا کال اسٹیک زیادہ سے زیادہ قابل اجازت گہرائی تک پہنچ جاتا ہے۔ OutOfMemoryError (Heap کی کمی) کے برعکس، StackOverflowError میموری کے ایک مختلف علاقے — اسٹیک سے متعلق ہے، جہاں میتھڈ کال فریم اور مقامی متغیرات محفوظ ہوتے ہیں۔

ہر میتھڈ کال اسٹیک میں ایک فریم بناتی ہے: واپسی کا پتہ، پیرامیٹرز اور مقامی متغیرات۔ میتھڈ سے واپسی پر فریم ختم ہو جاتا ہے۔ اگر کوئی میتھڈ بنیادی شرط کے بغیر خود کو کال کرتا ہے (ریکرشن)، تو فریم اسٹیک بھرنے تک جمع ہوتے رہتے ہیں۔ JVM نیا فریم مختص نہیں کر سکتا اور «null» پیغام (Java میں) یا لامتناہی طور پر دہرائی جانے والی اسٹیک لائن کے اشارے کے ساتھ StackOverflowError پھینکتا ہے۔

تھریڈ کے اسٹیک کا سائز تخلیق کے وقت مقرر ہوتا ہے اور عملدرآمد کے دوران تبدیل نہیں ہوتا۔ Android میں، مرکزی تھریڈ کا عام اسٹیک سائز 32–48 KB ہے، جو بہت زیادہ مقامی متغیرات کے بغیر میتھڈز کے لیے تقریباً 512–1024 فریم کی گہرائی دیتا ہے۔ پس منظر کے تھریڈز کے لیے، ڈیفالٹ سائز چھوٹا ہوتا ہے — 16–24 KB۔

کال اسٹیک کیسے کام کرتا ہے

کال اسٹیک (Call Stack) ایک LIFO (Last In, First Out) ڈیٹا ڈھانچہ ہے جو میتھڈ پر عملدرآمد کی ترتیب کا انتظام کرتا ہے۔ ہر بار جب پروگرام کسی میتھڈ کو کال کرتا ہے، JVM اسٹیک میں ایک فریم بناتا ہے اور اسے اوپر رکھتا ہے۔ جب میتھڈ مکمل ہوتا ہے، فریم ہٹا دیا جاتا ہے۔

ہر فریم میں شامل ہوتا ہے: اوپرینڈ اسٹیک (بائٹ کوڈ ہدایات کے لیے)، مقامی متغیرات کی صف (this سمیت)، مستقل پول کا حوالہ اور واپسی کا پتہ۔ میتھڈ میں جتنے زیادہ مقامی متغیرات ہوں گے، اس کے فریم کا سائز اتنا بڑا ہوگا اور اسٹیک بھرنے سے پہلے اتنے ہی کم میتھڈ کال کیے جا سکتے ہیں۔ 10 پیرامیٹرز اور 20 مقامی متغیرات والا میتھڈ بغیر پیرامیٹر والے میتھڈ کے مقابلے میں تقریباً 3 گنا زیادہ جگہ لیتا ہے۔

Android پر، ART ڈیسک ٹاپ JVM سے مختلف، اپنا اسٹیک نفاذ استعمال کرتا ہے۔ ART مخصوص حدود میں اسٹیک کو متحرک طور پر بڑھا سکتا ہے، لیکن ہر تھریڈ کے لیے ایک سخت حد اب بھی موجود ہے۔ مرکزی تھریڈ (UI تھریڈ) کا اسٹیک سب سے بڑا ہوتا ہے کیونکہ یہ پورے Activity لائف سائیکل اور ایونٹ پروسیسنگ کو سنبھالتا ہے۔

kotlin
// ریکرشن جو StackOverflowError کا باعث بنتی ہے
fun recursiveCall(depth: Int): Int {
    return recursiveCall(depth + 1) // کوئی بنیادی شرط نہیں
}

// کال ~1000 کی گہرائی پر StackOverflowError کا سبب بنے گی
recursiveCall(0)

اسٹیک اوورفلو کی بنیادی وجوہات

پانچ عام منظرنامے موبائل ایپلیکیشنز میں StackOverflowError کا سبب بنتے ہیں۔ ان میں سے زیادہ تر ریکرشن سے متعلق ہیں، لیکن کم واضح وجوہات بھی ہیں۔

بنیادی شرط کے بغیر لامتناہی ریکرشن

سب سے عام وجہ۔ ڈیولپر رکنے کی شرط کے بغیر یا ایسی شرط کے ساتھ ریکرسو میتھڈ لکھتا ہے جو کبھی true نہیں ہوتی۔ ہر کال ایک فریم شامل کرتی ہے، اور فریم کے سائز کے مطابق اسٹیک 500–2000 تکراروں میں بھر جاتا ہے۔ ایک عام مثال: n == 0 کی جانچ کیے بغیر n! فیکٹوریل کا حساب لگانا۔

ہر ریکرسو میتھڈ کے شروع میں بنیادی شرط چیک کریں۔ Kotlin میں، پیرامیٹر کی توثیق کے لیے require() یا check() استعمال کریں۔ گہری ریکرشن (100 سطحوں سے زیادہ) کے لیے، تکراری طریقہ کار سے تبدیل کرنے پر غور کریں۔

کنسٹرکٹرز میں چکری انحصار

کلاس A B کی مثال بناتا ہے، کلاس B A کی مثال بناتا ہے — یہ کنسٹرکٹرز میں چکری انحصار ہے۔ A بنانے کی کوشش پر، B کا کنسٹرکٹر کال ہوتا ہے، جو A کے کنسٹرکٹر کو کال کرتا ہے، اور یوں StackOverflowError تک۔ DI فریم ورک (Dagger, Hilt) مرتب وقت پر ایسے چکروں کا پتہ لگاتے ہیں، لیکن دستی آبجیکٹ تخلیق انہیں نہیں پکڑتی۔

انحصاری گراف کے ساتھ ڈیپنڈنسی انجیکشن استعمال کریں: Dagger یا Koin تعمیر کے وقت چکروں کی جانچ کرتے ہیں۔ اگر چکر ناگزیر ہے تو، براہ راست انحصار کو سست ابتداء یا Provider فیکٹری والے انٹرفیس سے تبدیل کریں۔

kotlin
// چکری انحصار — StackOverflowError
class A(private val b: B)
class B(private val a: A)

// سست حل
class A(private val bProvider: Provider<B>)

گراف ٹراورسل میں گہری ریکرشن

ریکرشن کے ذریعے View ٹری (ViewGroup.getChildAt())، فائل سسٹم یا JSON ڈھانچے کا ٹراورسل 500–1000 عناصر سے زیادہ کی گہرائی پر اسٹیک کی حد سے تجاوز کر سکتا ہے۔ 20 سطحوں کی نیسٹنگ والا Android ViewGroup نایاب ہے، لیکن 2000 نیسٹڈ آبجیکٹ والا ریکرسو JSON پارسنگ ایک حقیقی منظرنامہ ہے۔

ریکرسو ٹراورسل کو واضح Stack<T> یا ArrayDeque استعمال کرتے ہوئے تکراری ٹراورسل سے تبدیل کریں۔ یہ اسٹیک اوورفلو کے خطرے کو مکمل طور پر ختم کرتا ہے، کیونکہ heap آبجیکٹ اسٹیک کی حد سے محدود نہیں ہیں۔ Queue کے ذریعے BFS (چوڑائی سے پہلی تلاش) بھی مسئلہ حل کرتا ہے۔

onConfigurationChanged کی غلط ہینڈلنگ

Android-specific وجہ: کنفیگریشن کی غلط ہینڈلنگ پر لائف سائیکل میتھڈز کا چکری کال۔ مثال کے طور پر، onConfigurationChanged کے اندر recreate() کو کال کرنا، جو دوبارہ onConfigurationChanged کو کال کرتا ہے، اور یوں StackOverflowError تک۔ اسی طرح: onLayout() کے اندر setContentView()، جو ایک اور پیمائش اور ترتیب کو متحرک کرتا ہے۔

کنفیگریشن تبدیلیوں سے متعلق میتھڈز کے اندر recreate() کو کال نہ کریں۔ تھیم تبدیل کرتے وقت UI کو اپ ڈیٹ کرنے کے لیے، recreate کے بغیر setTheme() استعمال کریں۔ متحرک سمت تبدیلی کے لیے — کنفیگریشن میں فلیگ کے بغیر، requestOrientation() کو ایک بار کال کریں۔

چکری حوالوں کے ساتھ سیریلائزیشن

Gson، Moshi یا Kotlin Serialization جب چکری حوالوں (A، B کا حوالہ دیتا ہے، B، A کا حوالہ دیتا ہے) والے آبجیکٹ کو سیریلائز کرنے کی کوشش کرتے ہیں تو لامتناہی ریکرشن میں چلے جاتے ہیں اور StackOverflowError سے کریش ہو جاتے ہیں۔ دو طرفہ تعلقات (JPA, Room with ForeignKey) والی Entity کو سیریلائز کرتے وقت یہ ایک عام مسئلہ ہے۔

چکر کے ایک طرف @Transient، @JsonIgnore یا @kotlinx.serialization.Transient استعمال کریں۔ Gson کے لیے — واضح گہرائی کی حد کے ساتھ JsonSerializer۔ Room کے لیے — Entity کو کبھی براہ راست سیریلائز نہ کریں، DTO میپر استعمال کریں۔

StackOverflowError کی تشخیص اور اصلاح کیسے کریں

StackOverflowError کی تشخیص میموری کی دیگر خرابیوں سے آسان ہے: اسٹیک ٹریس زیادہ تر معاملات میں کال کا ایک دہرایا جانے والا سلسلہ دکھاتا ہے۔ یہ فوری طور پر ریکرشن کی طرف اشارہ کرتا ہے۔

اسٹیک ٹریس پڑھنا

StackOverflowError کا اسٹیک ٹریس منفرد ہے: پہلی 200–500 سطروں کے بعد، کال کا ایک ہی نمونہ دہرانا شروع ہو جاتا ہے۔ JVM آخر میں دہرائی جانے والی سطروں کو کاٹ دیتا ہے اور «... 1234 more» دکھاتا ہے۔ «...» سے پہلے غیر دہرائی جانے والی سطروں کی تعداد اس ریکرشن گہرائی کو ظاہر کرتی ہے جس نے خرابی پیدا کی۔

اسٹیک ٹریس کی پہلی سطریں پڑھیں — وہ ظاہر کرتی ہیں کہ کس میتھڈ سے دہراؤ شروع ہوا۔ وہ میتھڈ تلاش کریں جو خود کو کال کرتا ہے یا کال چین بناتا ہے جو اس پر واپس آتی ہے۔ بنیادی شرط درست کریں یا ریکرشن کو لوپ سے تبدیل کریں۔

اسٹیک سائز بڑھانا (عارضی حل)

عارضی طور پر، JVM فلیگ -Xss کے ذریعے اسٹیک سائز بڑھا کر مسئلہ حل کیا جا سکتا ہے۔ Android کے لیے، اسٹیک سائز AndroidManifest کے ذریعے مقرر کیا جاتا ہے: android:largeHeap اسٹیک کو متاثر نہیں کرتا۔ کوڈ میں تھریڈ اسٹیک بڑھانے کے لیے: Thread(ThreadGroup, Runnable, name, stackSize)۔ stackSize بائٹس میں مطلوبہ سائز ہے۔

kotlin
// بڑھائے گئے اسٹیک کے ساتھ تھریڈ بنانا
val thread = Thread(null, runnable, "big-stack-thread", 64 * 1024)
thread.start()

اہم: اسٹیک بڑھانے سے مسئلہ حل نہیں ہوتا، صرف تاخیر ہوتی ہے۔ 10,000 سطحوں کی ریکرشن پر، 64 KB کا اسٹیک 128 KB کے اسٹیک سے بدل دیا جائے گا، جو 20,000 سطحیں دے گا — لیکن خرابی پھر بھی ہوگی، بس بعد میں۔ واحد صحیح حل ریکرشن کی تکراری تبدیلی ہے۔

ریکرشن کو تکرار سے تبدیل کرنا

تکراری الگورتھم درمیانی حالتیں ذخیرہ کرنے کے لیے کال اسٹیک استعمال نہیں کرتے — وہ انہیں heap میں ذخیرہ کرتے ہیں (Stack<T> یا ArrayDeque)۔ بائنری ٹری ٹراورسل، فیکٹوریل حساب، فبونیکی — کسی بھی ریکرشن کو واضح اسٹیک استعمال کرتے ہوئے تکرار میں تبدیل کیا جا سکتا ہے۔

kotlin
// تکراری درخت ٹراورسل — StackOverflow کا کوئی خطرہ نہیں
fun traverseIterative(root: Node?) {
    val stack = ArrayDeque<Node>()
    stack.push(root)
    while (stack.isNotEmpty()) {
        val node = stack.pop() ?: continue
        process(node)
        node.right?.let { stack.push(it) }
        node.left?.let { stack.push(it) }
    }
}

Stack Overflow کو کیسے روکیں

StackOverflowError کی روک تھام قواعد اور اوزاروں کا ایک مجموعہ ہے جو ممکنہ ریکرسو چکروں کی پیداوار تک پہنچنے سے پہلے نشاندہی کرتا ہے۔

ڈیبگ بلڈ میں ریکرشن گہرائی کی حد

ڈیبگ بلڈز میں ریکرسو میتھڈز میں ایک حفاظتی گہرائی کاؤنٹر شامل کریں۔ اگر گہرائی ایک حد (مثلاً 1000) سے تجاوز کر جائے تو واضح پیغام کے ساتھ ایک استثنا پھینکیں۔ یہ ناقابل پڑھنے ٹریس والے StackOverflowError کو قابل فہم کاروباری استثنا میں بدل دیتا ہے۔

kotlin
fun safeRecursive(n: Int, depth: Int = 0): Int {
    if (depth > 1000) {
        throw IllegalStateException("ریکرشن 1000 سطحوں سے تجاوز کر گئی")
    }
    return if (n <= 1) n
           else safeRecursive(n - 1, depth + 1)
}

جامد کوڈ تجزیہ

Detekt (Kotlin) اور Infer (Facebook) جامد تجزیہ کی سطح پر ممکنہ لامتناہی ریکرشنز تلاش کرتے ہیں۔ Detekt میں PotentiallyInfiniteRecursion اصول ہے جو پیرامیٹر تبدیل کیے بغیر خود کال کے بارے میں خبردار کرتا ہے۔ اسے CI اصولوں کے سیٹ میں فعال کریں اور شدت کو error پر سیٹ کریں۔

ریکرشن پر توجہ کے ساتھ کوڈ کا جائزہ

کوڈ کے جائزے میں، ان پر توجہ دیں: کوئی خود کال میتھڈ، لیمبڈا کے اندر ریکرسو کال (Kotlin ان لائن فنکشنز)، مختلف کلاسز کے درمیان چکری کال، پراپرٹی ڈیلیگیٹ میں ریکرشن۔ ہر ریکرسو میتھڈ کے لیے چیک کریں: کیا بنیادی شرط ہے، کیا پیرامیٹر ہر قدم پر بدلتا ہے، کیا پیرامیٹر کی تبدیلی بنیادی شرط تک پہنچنے کی ضمانت دیتی ہے۔

دمی-ریکرسو تبدیلی (محدود)

Kotlin tailrec موڈیفائر کو سپورٹ کرتا ہے: اگر کوئی ریکرسو میتھڈ tailrec سے نشان زد ہے اور کال دمی (آخری آپریشن) ہے تو مرتب اسے تکرار میں تبدیل کر دیتا ہے۔ تاہم، tailrec صرف خود کال (میتھڈ براہ راست خود کو کال کرتا ہے) کے لیے کام کرتا ہے، باہمی ریکرشن کے لیے کام نہیں کرتا، اور Android کے مطابق Kotlin ورژن 1.5 سے پہلے سپورٹ نہیں ہوتا۔

kotlin
tailrec fun factorial(n: Int, acc: Int = 1): Int {
    return if (n <= 1) acc
           else factorial(n - 1, acc * n) // دمی کال
}

اکثر پوچھے گئے سوالات

کیا StackOverflowError کو try-catch سے پکڑا جا سکتا ہے؟

ہاں، لیکن صرف Java کی سطح پر۔ Error، Exception کی طرح، Throwable ہے۔ تاہم، StackOverflowError کے بعد اسٹیک خراب ہو جاتا ہے — جو فریم فٹ نہیں ہو سکے وہ صحیح طریقے سے مکمل نہیں ہو سکتے۔ catch بلاک میں نیا آبجیکٹ بنانے کی کوشش دوسرا StackOverflowError پیدا کر سکتی ہے۔

Android میں ڈیفالٹ اسٹیک سائز کیا ہے؟

مرکزی تھریڈ کے لیے — 32–48 KB، پس منظر کے تھریڈز کے لیے — 16–24 KB۔ صحیح سائز Android ورژن اور ڈیوائس بنانے والے پر منحصر ہے۔ ART متحرک اسٹیک توسیع استعمال کرتا ہے لیکن ابتدائی قدر سے 2× سے زیادہ نہیں۔

کیا دمی ریکرشن StackOverflowError کو روک سکتی ہے؟

Kotlin میں — ہاں، اگر میتھڈ tailrec سے نشان زد ہے۔ مرتب دمی ریکرشن کو تکرار میں تبدیل کرتا ہے، اسٹیک کی نشوونما کو مکمل طور پر ختم کرتا ہے۔ Java میں، دمی ریکرشن JVM کے ذریعے بہتر نہیں کی جاتی (Scala جیسی فنکشنل زبانوں کے برعکس)۔

ایمولیٹر پر StackOverflowError کیوں ہوتا ہے لیکن ڈیوائس پر نہیں؟

اسٹیک کا سائز ایمولیٹر اور حقیقی ڈیوائس پر مختلف ہو سکتا ہے۔ ایمولیٹر عام 512–1024 KB اسٹیک والی ڈیسک ٹاپ JVM استعمال کرتا ہے، جبکہ Android ART 32–48 KB استعمال کرتا ہے۔ خرابی ڈیسک ٹاپ JVM سے پہلے ART پر ظاہر ہوگی۔

StackOverflowError، OutOfMemoryError سے کیسے مختلف ہے؟

میموری کا علاقہ: StackOverflowError اسٹیک خرابی (کال فریم) ہے، OutOfMemoryError heap خرابی (آبجیکٹ) ہے۔ StackOverflowError تقریباً ہمیشہ ریکرشن کی وجہ سے ہوتا ہے، جبکہ OutOfMemoryError میموری لیک یا بڑے آبجیکٹ کی وجہ سے ہوتا ہے۔

خلاصہ

  • StackOverflowError — ریکرشن گہرائی کی حد سے تجاوز کرنے پر کال اسٹیک اوورفلو
  • Android میں اسٹیک گہرائی مرکزی تھریڈ پر 512–1024 فریم ہے
  • لامتناہی ریکرشن بنیادی وجہ ہے؛ ہر ریکرسو میتھڈ میں بنیادی شرط چیک کریں
  • کنسٹرکٹرز میں چکری انحصار — کم واضح لیکن عام اوورفلو وجہ
  • واضح Stack<T> کے ذریعے ریکرشن کی تکراری تبدیلی خطرے کو مکمل طور پر ختم کرتی ہے
  • Kotlin میں tailrec دمی ریکرشن کو مرتب کی سطح پر تکرار میں تبدیل کرتا ہے
  • جامد تجزیہ (Detekt, Infer) رن ٹائم سے پہلے ممکنہ لامتناہی ریکرشن تلاش کرتا ہے

ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے

IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔

پروجیکٹ پر بحث کریں

مزید پڑھیں