Heisenbug: یہ کیا ہے، کیوں ہوتا ہے اور پکڑنے کے طریقے

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

Heisenbug — ایک بگ جو ڈیبگ کرنے کی کوشش کرنے پر غائب ہو جاتا ہے۔ یہ اصطلاح ہائیزنبرگ کے غیر یقینی اصول سے ماخوذ ہے: مشاہدہ نظام کے رویے کو متاثر کرتا ہے۔ موبائل ڈویلپمنٹ میں، Heisenbug سب سے مشکل مسائل میں سے ایک ہے کیونکہ ڈیبگنگ کے معیاری طریقے (لاگز، بریک پوائنٹس، اضافی کوڈ) پروگرام کی حالت بدل دیتے ہیں اور بگ چھپا دیتے ہیں۔ آئیے اسباب اور مشکل سے پکڑے جانے والی غلطیوں سے نمٹنے کے طریقے سمجھتے ہیں۔

اہم نکات

  • Race condition — Heisenbug کی بنیادی وجہ: ڈیبگنگ کے دوران ٹائمنگ تبدیل کرنا مسئلہ چھپا دیتا ہے
  • Bohrbug — ایک پیش قیاسی بگ، Heisenbug کے برعکس آسانی سے دوبارہ پیدا کیا جا سکتا ہے
  • Mandelbug — پیچیدہ وجہ اور اثر کے تعلقات والا بگ، ابتدائی حالات کے لیے حساس
  • ThreadSanitizer — ڈیٹا ریس کا پتہ لگانے کا آلہ جو ٹائمنگ متاثر نہیں کرتا
  • تعینی ٹیسٹ — Heisenbug کو دوبارہ پیدا کرنے کا واحد قابل اعتماد طریقہ

موبائل ڈویلپمنٹ میں Heisenbug کیا ہے؟

Heisenbug — غلطیوں کا ایک طبقہ جو پروڈکشن یا عام آپریشن میں ظاہر ہوتا ہے، لیکن ڈیبگنگ ماحول میں دوبارہ پیدا کرنے کی کوشش کرنے پر غائب ہو جاتا ہے۔ یہ اصطلاح 1980 کی دہائی میں پروگرامر Jim Gray نے تقسیم شدہ نظاموں کے سیاق و سباق میں وضع کی تھی، لیکن آج یہ موبائل ایپلیکیشنز کے لیے ان کی غیر متزامن نوعیت کی وجہ سے سب سے زیادہ متعلقہ ہے۔

بنیادی وجہ: معیاری ڈیبگنگ ٹولز عملدرآمد کے ماحول کو بدل دیتے ہیں۔ ایک بریک پوائنٹ تھریڈ کو کئی ملی سیکنڈ کے لیے روکتا ہے، لاگنگ ہم وقت ساز I/O شامل کرتی ہے، اضافی جانچ آپریشنز کی ترتیب بدل دیتی ہے۔ ملٹی تھریڈ ماحول میں، مائیکرو سیکنڈ کی تاخیر بھی تھریڈ عملدرآمد کی ترتیب بدل سکتی ہے اور ڈیٹا ریس چھپا سکتی ہے۔

Microsoft Research (2022) کے مطابق، ملٹی تھریڈ موبائل ایپلیکیشنز میں تقریباً 15-25% بگز Heisenbug کے طور پر درجہ بند کیے جاتے ہیں۔ ساتھ ہی، ایک Heisenbug کو تلاش کرنے اور ٹھیک کرنے میں لگنے والا وقت عام بگ سے اوسطاً 5-10 گنا زیادہ ہوتا ہے، کیونکہ اسے براہ راست دوبارہ پیدا نہیں کیا جا سکتا۔

Heisenbug کی مثال

فہرست میں تیزی سے سوائپ کرنے پر ایپ پروڈکشن میں کریش ہو جاتی ہے، لیکن ڈیبگر سے منسلک ہونے یا لاگز شامل کرنے پر — یہ بالکل کام کرتی ہے۔ وجہ: UI تھریڈ (RecyclerView اپ ڈیٹ) اور بیک گراؤنڈ تھریڈ (اڈاپٹر ڈیٹا اپ ڈیٹ) کے درمیان ڈیٹا ریس۔ لاگز ایک تاخیر شامل کرتے ہیں جو تھریڈز کو تصادفی طور پر ہم آہنگ کرتی ہے۔

Bohrbug، Mandelbug، Heisenbug: بگز کی درجہ بندی

Bohrbug — ایک پیش قیاسی، مستحکم طور پر دوبارہ پیدا ہونے والا بگ۔ بوہر کے ایٹمی ماڈل سے تشبیہ دے کر نامزد کیا گیا: ایٹم کی طرح، بگ ہر بار مشاہدہ کرنے پر یکساں رویہ دکھاتا ہے۔ مثال: ڈیٹا لوڈ ہونے سے پہلے بٹن دبانے پر NullPointerException۔ معیاری یونٹ ٹیسٹنگ سے علاج۔

Mandelbug — پیچیدہ، افراتفری والے وجہ اور اثر کے تعلقات والا بگ (مینڈل بروٹ سیٹ سے تشبیہ دے کر نامزد کیا گیا)۔ صرف حالات کے ایک مخصوص امتزاج کے تحت ظاہر ہوتا ہے: OS ورژن، ڈیوائس ماڈل، نیٹ ورک کی حالت۔ یہ Heisenbug سے اس لحاظ سے مختلف ہے کہ یہ ڈیبگنگ کے دوران غائب نہیں ہوتا — مسئلہ دوبارہ پیدا کرنے کی مشکل ہے، اوزاروں سے رویہ تبدیل ہونا نہیں۔

Heisenbug — ایک بگ جو خاص طور پر ڈیبگنگ ٹولز کی وجہ سے غائب ہو جاتا ہے۔ اگر آپ لاگ شامل کرتے ہیں — بگ غائب ہو جاتا ہے۔ اگر آپ بریک پوائنٹ لگاتے ہیں — بگ ظاہر نہیں ہوتا۔ اگر آپ سب کچھ ہٹا دیتے ہیں — بگ واپس آ جاتا ہے۔ بنیادی وجہ: ڈیبگنگ کے دوران تبدیل شدہ ٹائمنگ۔

قسمدوبارہ پیدا کرنے کی صلاحیتڈیبگنگ پر ردعملمثال
Bohrbug100%بدستورخالی فہرست پر NPE
MandelbugافراتفریبدستورAndroid 12، Samsung، کم بیٹری پر کریش
Heisenbugصرف ڈیبگنگ کے بغیرغائبلاگز سے غائب ہونے والی ڈیٹا ریس
Schrödinbugکوڈ میں ظاہر نہیں ہوتادیکھنے پر ظاہربگ کوڈ میں نظر آتا ہے لیکن کبھی متحرک نہیں ہوتا

Heisenbug کے اہم اسباب

Race condition — Heisenbug کی پہلی وجہ۔ دو تھریڈ ہم آہنگی کے بغیر مشترکہ ڈیٹا تک رسائی حاصل کرتے ہیں۔ ڈیبگر ایک تاخیر متعارف کراتا ہے، جس سے تھریڈ قدرتی طور پر ہم آہنگ ہو جاتے ہیں۔ ڈیبگر کے بغیر، عملدرآمد کی ترتیب غیر متوقع ہے۔

ٹائمنگ پر منحصر غلطیاں — بگز جو صرف ایک مخصوص عملدرآمد کی رفتار پر ظاہر ہوتے ہیں۔ مثال: ایک اینیمیشن جو اگلے آپریشن کے شروع ہونے سے پہلے ختم ہونی چاہیے۔ ڈیبگر میں، اینیمیشن سست چلتی ہے اور آپریشن اینیمیشن ختم ہونے کے بعد شروع ہونے کا وقت پا لیتا ہے۔ پروڈکشن میں — اس کے برعکس۔

kotlin
// Example race condition — typical Heisenbug
class ListViewModel : ViewModel() {
    private var items = mutableListOf<String>()

    fun loadFromNetwork() {
        viewModelScope.launch(Dispatchers.IO) {
            val result = api.fetchItems()
            items.addAll(result) // ❌ Not thread-safe
        }
    }

    fun getItems(): List<String> = items.toList()
    // Race condition: getItems read may overlap with loadFromNetwork write
}

کمپائلر آپٹیمائزیشن — کمپائلر (JIT، ART، Kotlin/Native) آپٹیمائزیشن کے لیے ہدایات کو دوبارہ ترتیب دے سکتا ہے۔ ڈیبگ بلڈ میں، آپٹیمائزیشن غیر فعال ہوتی ہیں اور کوڈ «جیسا لکھا گیا ہے» ویسا ہی عملدرآمد ہوتا ہے۔ ریلیز بلڈ میں، کمپائلر آپریشنز کی ترتیب بدل دیتا ہے، جو کوڈ میں چھپی ہوئی مفروضوں کو ظاہر کر سکتا ہے۔

  • ThreadLocal — تھریڈ لوکل متغیرات کا غلط استعمال جو دوسرے تھریڈز کو نظر نہیں آتے
  • غیر ابتدائی شدہ متغیرات — کوڈ جو کلاس فیلڈز کی ڈیفالٹ اقدار پر انحصار کرتا ہے
  • GCD/dispatch قطاریں — iOS میں، متوازی قطاروں میں بلاک عملدرآمد کی غیر متعینہ ترتیب
  • بفر شدہ I/O — بفر بھرنے تک ڈیٹا ڈسک پر نہیں لکھا جاتا

مشکل بگز پکڑنے کی حکمت عملی

ThreadSanitizer (TSan) — C/C++ اور Kotlin/Native میں ڈیٹا ریس کا پتہ لگانے کا گوگل کا آلہ۔ یہ بلڈ میں شامل ہوتا ہے اور ہم آہنگی کے بغیر کسی بھی مشترکہ میموری تک رسائی کا پتہ لگاتا ہے۔ لاگز کے برعکس، TSan ٹائمنگ کو متاثر نہیں کرتا کیونکہ یہ I/O کے بجائے انسٹرومینٹڈ کوڈ کے ذریعے کام کرتا ہے۔

تعینی ٹیسٹ — حقیقی غیر متزامنیت کو کنٹرول شدہ غیر متزامنیت سے بدلیں۔ عملدرآمد کی ترتیب پر مکمل کنٹرول کے لیے TestDispatcher (Kotlin)، RxJava Plugins یا GCD ٹیسٹ قطاریں (iOS) استعمال کریں۔ مخصوص منظرنامے طے کریں: تھریڈ A چلتا ہے، پھر B، پھر دوبارہ A۔

چکریہ لاگنگ — میموری میں رنگ بفر میں لاگنگ (ڈسک پر نہیں)۔ جب بگ ہوتا ہے، بفر فائل میں محفوظ کیا جاتا ہے۔ چونکہ میموری میں لکھنے میں نینو سیکنڈ لگتے ہیں (ڈسک I/O کے لیے ملی سیکنڈ کے بجائے)، ایسی لاگنگ ٹائمنگ کو متاثر نہیں کرتی اور Heisenbug کو نہیں چھپاتی۔

kotlin
class CyclicBuffer(val capacity: Int = 1000) {
    private val buffer = ArrayDeque<String>(capacity)
    private val lock = Any()

    fun log(message: String) {
        synchronized(lock) {
            if (buffer.size >= capacity) buffer.removeFirst()
            buffer.addLast(message)
        }
    }

    fun flush() {
        synchronized(lock) { buffer.forEach { fileWriter.write(it) } }
    }
}

پروڈکشن میں لاگنگ — اگر بگ مقامی طور پر دوبارہ پیدا نہیں ہوتا، تو پروڈکشن میں ڈیٹا جمع کریں۔ Firebase Crashlytics لاگز، Sentry Breadcrumbs یا کسٹم چکریہ لاگر استعمال کریں۔ اہم: لاگنگ غیر متزامن ہونی چاہیے اور کارکردگی پر کم سے کم اثر ڈالنی چاہیے۔

آرکیٹیکچر کی سطح پر Heisenbug سے بچاؤ

حالت کی علیحدگی — مشترکہ قابل تبدیل حالت کو کم سے کم کریں۔ ہر جزو کی اپنی الگ تھلگ حالت ہونی چاہیے، جو دوسرے اجزاء سے براہ راست لکھنے کے لیے ناقابل رسائی ہو۔ Unidirectional Data Flow (UDF) استعمال کریں — حالت ایک سمت میں بہتی ہے: واقعہ → کم کرنے والا → حالت → UI۔

فعالی طریقہ — ضمنی اثرات کے بغیر خالص افعال کی جانچ اور ڈیبگ کرنا آسان ہے۔ ضمنی اثرات (نیٹ ورک، DB، فائلیں) سختی سے متعین تہوں (ریپوزٹری، ڈیٹا سورس) میں الگ کریں۔ فعالی کوڈ میں تھریڈنگ کی غلطیاں عملی طور پر ناممکن ہیں۔

سخت موڈ — ڈیبگ بلڈ میں Android StrictMode فعال کریں۔ یہ تھریڈنگ پالیسی کی خلاف ورزیاں (مین تھریڈ پر نیٹ ورک، مین تھریڈ پر ڈسک I/O) کا پتہ لگاتا ہے اور ایک استثنا پھینکتا ہے۔ یہ ممکنہ Heisenbug کو ایک تعینی Bohrbug میں بدل دیتا ہے جو فوری طور پر نظر آتا ہے۔

kotlin
class DebugApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        if (BuildConfig.DEBUG) {
            StrictMode.setThreadPolicy(
                StrictMode.ThreadPolicy.Builder()
                    .detectDiskReads()
                    .detectDiskWrites()
                    .detectNetwork()
                    .penaltyLog()
                    .build()
            )
        }
    }
}

غیر متزامنیت پر توجہ کے ساتھ کوڈ کا جائزہ — عمل کا ایک لازمی حصہ۔ ہر پل ریکویسٹ کو مشترکہ قابل تبدیل حالت، غیر تھریڈ سیف کلیکشنز اور ہم آہنگی کی کمی کے لیے چیک کیا جانا چاہیے۔ مخصوص پیٹرن کو خودکار طور پر منع کرنے کے لیے lint اصول استعمال کریں (مثال: synchronized کے بغیر MutableList تک رسائی)۔

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

Heisenbug کو تلاش کرنا اتنا مشکل کیوں ہے؟

کیونکہ معیاری طریقے — بریک پوائنٹس، لاگز، print — عملدرآمد کے ماحول کو اتنا بدل دیتے ہیں کہ بگ ظاہر ہونا بند ہو جاتا ہے۔ ڈیبگر تمام تھریڈز کو دسیوں ملی سیکنڈ کے لیے روکتا ہے۔ اس دوران، ڈیٹا ریس جو بگ پیدا کر رہی تھی، قدرتی طور پر حل ہو جاتی ہے۔ ایسے اوزار درکار ہیں جو عملدرآمد کی ٹائمنگ کو متاثر نہ کریں۔

Heisenbug Mandelbug سے کیسے مختلف ہے؟

Mandelbug حالات کی پیچیدگی کی وجہ سے دوبارہ پیدا کرنا مشکل ہے، لیکن ڈیبگنگ ٹولز اس کے ظہور کو متاثر نہیں کرتے۔ Heisenbug خاص طور پر ڈیبگنگ ٹولز کی وجہ سے غائب ہو جاتا ہے۔ Mandelbug کی مثال: صرف Android 11، 3 GB RAM اور 15% سے کم بیٹری والے آلات پر کریش۔ Heisenbug کی مثال: Log.d() شامل کرنے پر غائب ہونے والی ڈیٹا ریس۔

CI/CD میں Heisenbug کی جانچ کیسے کریں؟

Flaky test detection استعمال کریں — ٹیسٹ جو کبھی ناکام ہوتے ہیں، کبھی کامیاب۔ Android میں، ٹیسٹ تنہائی کے لیے Android Test Orchestrator استعمال کریں۔ ڈیبگ ٹیسٹ میں StrictMode شامل کریں۔ بلڈ کو ThreadSanitizer سے انسٹرومینٹ کریں۔ اگر ٹیسٹ >5% رنز میں flaky ہے — اسے ممکنہ Heisenbug سمجھیں اور انضمام سے پہلے تحقیق کریں۔

کیا Flow/Coroutines Heisenbug سے بچنے میں مدد دیتے ہیں؟

جزوی طور پر۔ Kotlin میں Flow اور ساختہ ہم آہنگی مشترکہ قابل تبدیل حالت کی مقدار کم کرتے ہیں اور تھریڈ مینجمنٹ آسان بناتے ہیں۔ لیکن coroutines تھریڈ سیفٹی کی ضمانت نہیں دیتے: اگر دو coroutines حالت بانٹتے ہیں، تو ڈیٹا ریس اب بھی ممکن ہے۔ مشترکہ حالت کے تحفظ کے لیے Mutex یا coroutines کے درمیان ڈیٹا منتقل کرنے کے لیے Channel استعمال کریں۔

اگر Heisenbug صرف پروڈکشن میں ظاہر ہو تو کیا کریں؟

میموری میں چکریہ لاگ بفر استعمال کریں جو غلطی پر خودکار طور پر فلش ہو۔ کسٹم breadcrumbs کے ساتھ Crashlytics یا Sentry کے ذریعے تفصیلی نگرانی شامل کریں۔ Android کے لیے، ANR کا پتہ لگانا فعال کریں اور traces دیکھیں۔ اگر بگ ڈیٹا ریس ہے، تو پروڈکشن جیسے لوڈ کے ساتھ ڈیبگ بلڈ میں ThreadSanitizer مسئلہ ظاہر کر سکتا ہے۔

خلاصہ

  • Heisenbug — ڈیبگ کرنے کی کوشش پر غائب ہونے والا بگ؛ بنیادی وجہ ڈویلپر ٹولز سے ٹائمنگ تبدیل ہونا
  • Race condition — موبائل ایپلیکیشنز، خاص طور پر غیر متزامن کوڈ میں Heisenbug کی بنیادی وجہ
  • Bohrbug (100% دوبارہ پیدا ہونے والا) اور Mandelbug (افراتفری) — بگ کی دیگر اقسام، Heisenbug سے نہ الجھائیں
  • ThreadSanitizer — عملدرآمد کی ٹائمنگ متاثر کیے بغیر ڈیٹا ریس کا پتہ لگانے کا بہترین آلہ
  • ڈسک کے بجائے میموری میں چکریہ لاگنگ — Heisenbug کو چھپائے بغیر ڈیٹا جمع کرنے کا طریقہ
  • Unidirectional Data Flow اور مشترکہ قابل تبدیلی حالت کو کم سے کم کرنا — غلطیوں کی پوری کلاس کی آرکیٹیکچرل روک تھام
  • ڈیبگ بلڈ میں StrictMode ممکنہ Heisenbug کو فوری طور پر نظر آنے والے تعینی Bohrbug میں بدل دیتا ہے

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

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

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

مزید پڑھیں