डेवलपमेंट में फ़्रीज़ — सार, कारण और रोकथाम

लेखक: IT Sectr प्रकाशित: 2026-07-28 पढ़ने का समय: 9 मिनट

फ़्रीज़ (हैंग) एक ऐसी स्थिति है जिसमें मोबाइल ऐप्लिकेशन लंबे समय तक उपयोगकर्ता की किसी भी कार्रवाई पर प्रतिक्रिया देना बंद कर देता है। लैग (धीमापन) और ग्लिच (गलत व्यवहार) के विपरीत, फ़्रीज़ UI को पूरी तरह से ब्लॉक कर देता है: टच प्रोसेस नहीं होते, एनिमेशन रुक जाता है, स्क्रीन “जम जाती है”। कारण है सिंक्रोनस ऑपरेशन द्वारा मुख्य थ्रेड का ब्लॉक होना, मल्टीथ्रेडेड कोड में डेडलॉक, या असामान्य रूप से लंबा गार्बेज कलेक्शन। Apple Main Thread Checker दस्तावेज़ीकरण के अनुसार, iOS के 40% से अधिक क्रैश रिपोर्ट मुख्य थ्रेड ब्लॉकिंग से संबंधित हैं। Android पर, ऐसी ही स्थिति ANR — सिस्टम डायलॉग “ऐप रिस्पॉन्ड नहीं कर रहा” — की ओर ले जाती है।

मुख्य बिंदु

  • फ़्रीज़ — लंबे समय के लिए UI का पूर्ण ब्लॉक होना (सेकंड और दसियों सेकंड), जो लैग और ग्लिच से अलग है
  • मुख्य कारण — I/O द्वारा मुख्य थ्रेड का ब्लॉक होना, थ्रेड्स के बीच डेडलॉक, अनंत लूप और लंबे GC के साथ मेमोरी लीक
  • निदान में iOS पर Main Thread Checker, Android पर ANR लॉग /data/anr/traces.txt और थ्रेड डंप विश्लेषण शामिल है
  • समाधान — सभी संभावित लंबी कार्रवाइयों को बैकग्राउंड थ्रेड्स पर ले जाना, Structured Concurrency का उपयोग और UI थ्रेड में synchronized से बचना
  • रोकथाम — StrictMode, Debug स्कीम में Main Thread Checker, डेडलॉक के लिए स्थैतिक विश्लेषण और प्रतिक्रिया समय मापने वाले नियमित परीक्षण

मोबाइल डेवलपमेंट में फ़्रीज़ क्या है

फ़्रीज़ (हैंग) मोबाइल ऐप्लिकेशन में एक ऐसी स्थिति है जहाँ ऐप कई सेकंड या उससे अधिक समय तक इनपुट इवेंट प्रोसेस करना और इंटरफ़ेस अपडेट करना बंद कर देता है। तकनीकी रूप से, इसका मतलब है कि मुख्य थ्रेड ब्लॉक हो गया है और अगला रन लूप इटरेशन निष्पादित नहीं कर सकता।

फ़्रीज़, लैग और ANR के बीच अंतर

लैग 500 ms तक की देरी है जिसमें उपयोगकर्ता धीमापन नोटिस करता है लेकिन ऐप काम करता रहता है। फ़्रीज़ 1 सेकंड से लेकर दसियों सेकंड तक रहता है। Android पर ANR फ़्रीज़ का एक विशेष मामला है जो 5 सेकंड से अधिक समय तक रहा और सिस्टम द्वारा डिटेक्ट किया गया। हर फ़्रीज़ ANR नहीं लाता, लेकिन हर ANR एक सिस्टम-डॉक्यूमेंटेड फ़्रीज़ है।

फ़्रीज़ के परिणाम

Android पर, 5 सेकंड से अधिक का फ़्रीज़ ANR डायलॉग ट्रिगर करता है जो ऐप बंद करने का सुझाव देता है। iOS पर, सिस्टम में एक वॉचडॉग है — अगर ऐप 10–20 सेकंड तक इवेंट पर प्रतिक्रिया नहीं देता, तो वॉचडॉग प्रोसेस को कोड 0x8badf00d (ate bad food) के साथ समाप्त कर देता है। उपयोगकर्ता केवल ऐप को अचानक होम स्क्रीन पर बंद होते देखता है।

Android और iOS पर फ़्रीज़ के कारण

कोई भी ऑपरेशन जो 100 ms से अधिक समय लेता है और मुख्य थ्रेड पर चलाया जाता है, संभावित रूप से फ़्रीज़ का कारण बन सकता है। आइए ब्लॉकेज के मुख्य स्रोतों को देखें।

UI थ्रेड में सिंक्रोनस I/O

बड़ी फ़ाइल पढ़ना, बिना एसिंक्रोनी के नेटवर्क रिक्वेस्ट, SharedPreferences में सिंक्रोनस apply विधि के बाद commit द्वारा डेटा सेव करना — ये सभी ऑपरेशन मुख्य थ्रेड को ब्लॉक करते हैं। Android पर, 10 MB फ़ाइल को सिंक्रोनस रूप से पढ़ने में फ़्लैश मेमोरी स्पीड के आधार पर 200–500 ms लग सकते हैं। iOS पर, completionHandler के बिना सिंक्रोनस URLSession लोड सर्वर प्रतिक्रिया समय के लिए UI को ब्लॉक करता है।

मल्टीथ्रेडेड कोड में डेडलॉक

जब दो थ्रेड एक-दूसरे द्वारा धारित संसाधनों की प्रतीक्षा करते हैं, तो डेडलॉक होता है। मोबाइल ऐप्लिकेशन में, एक विशिष्ट परिदृश्य है: थ्रेड A Lock1 को लॉक करता है और Lock2 की प्रतीक्षा करता है, जबकि थ्रेड B Lock2 को लॉक करता है और Lock1 की प्रतीक्षा करता है। दोनों थ्रेड हमेशा के लिए फ़्रीज़ हो जाते हैं। यदि उनमें से एक मुख्य थ्रेड है, तो ऐप पूरी तरह फ़्रीज़ हो जाता है।

अनंत लूप या रिकर्शन

लॉजिक में त्रुटि — उदाहरण के लिए, बिना exit कंडीशन के while(true) या बिना बेस केस के रिकर्शन — मुख्य थ्रेड पर अनंत निष्पादन की ओर ले जाती है। Android इसे 5 सेकंड के बाद ANR के माध्यम से डिटेक्ट करता है, iOS — स्टैकशॉट के माध्यम से, जो अनंत रूप से दोहराए जाने वाले कॉल स्टैक को कैप्चर करता है।

  • Android — बिना बंद किया गया Cursor, enqueue() के बजाय execute() के माध्यम से सिंक्रोनस रिक्वेस्ट, UI थ्रेड में FileInputStream.read()
  • iOS — performSelectorOnMainThread:withObject:waitUntilDone:YES, NSURLConnection sendSynchronousRequest लॉन्च करना, dataWithContentsOfURL के साथ इमेज लोड करना
  • क्रॉस-प्लेटफ़ॉर्म — समर्पित isolate के बिना Flutter compute, सिंक्रोनस React Native NativeModule

फ़्रीज़ का निदान कैसे करें

फ़्रीज़ के निदान के लिए ऐसे उपकरण चाहिए जो ब्लॉकेज के क्षण में सभी थ्रेड्स की स्थिति को कैप्चर कर सकें।

Android पर ANR लॉग

प्रत्येक ANR पर, Android सिस्टम एक फ़ाइल /data/anr/traces.txt सेव करता है जिसमें प्रत्येक ऐप थ्रेड का स्टैक डंप होता है। इस फ़ाइल का विश्लेषण मुख्य निदान विधि है: main थ्रेड खोजें और देखें कि वह किस विधि पर रुका है। यदि स्टैक Thread.sleep, InputStream.read या Lock.lock पर समाप्त होता है — कारण मिल गया।

iOS पर स्टैकशॉट

Xcode ऐप के फ़्रीज़ होने पर (SIGSTOP सिग्नल) स्टैकशॉट — सभी थ्रेड स्टैक का स्नैपशॉट — ले सकता है। स्कीम में “Logging” → “Include Stackshot Logs” सक्षम करें। कोड 0x8badf00d के साथ क्रैश पर, Devices & Simulators से क्रैश लॉग निकालें और अटके स्टैक के साथ com.apple.main-thread खोजें।

Xcode में Main Thread Checker

Main Thread Checker ऐप चलने के दौरान बैकग्राउंड थ्रेड से UIKit कॉल को स्वचालित रूप से डिटेक्ट करता है। इसे स्कीम में सक्षम करें (Diagnostics → Main Thread Checker)। प्रत्येक चेतावनी फ़्रीज़ का संभावित कारण है, विशेषकर यदि यह नेटवर्क रिक्वेस्ट completionHandler क्लोज़र में होती है।

Android पर StrictMode के माध्यम से ब्लॉकेज डिटेक्शन का उदाहरण:

kotlin
class App : Application() {
    override fun onCreate() {
        super.onCreate()
        StrictMode.setVmPolicy(StrictMode.VmPolicy.Builder()
            .detectLeakedSqlLiteObjects()
            .detectLeakedClosableObjects()
            .penaltyLog()
            .build())
        StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder()
            .detectAll()
            .penaltyDeath()
            .build())
    }
}

UI ब्लॉकेज को खत्म करने के तरीके

फ़्रीज़ को खत्म करना सभी संभावित लंबी कार्रवाइयों को बैकग्राउंड थ्रेड्स पर ले जाने से शुरू होता है। आइए प्रत्येक प्लेटफ़ॉर्म के लिए विशिष्ट तकनीकें देखें।

कोरूटीन के साथ स्ट्रक्चर्ड कन्करेंसी

Kotlin Coroutines viewModelScope.launch(Dispatchers.IO) के साथ गारंटी देते हैं कि नेटवर्क ऑपरेशन या डेटाबेस रीड बैकग्राउंड थ्रेड पर निष्पादित हों। Dispatchers.Main का उपयोग केवल UI अपडेट के लिए किया जाता है। महत्वपूर्ण: सभी suspend फ़ंक्शन स्ट्रक्चर्ड होने चाहिए — चाइल्ड कोरूटीन पैरेंट के कैंसल होने पर कैंसल हो जाते हैं, जिससे थ्रेड लीक रुकता है।

iOS पर एसिंक्रोनस क्यू

Grand Central Dispatch बैकग्राउंड कार्यों के लिए DispatchQueue.global(qos: .userInitiated) और UI अपडेट के लिए DispatchQueue.main.async के साथ मानक पैटर्न है। मुख्य क्यू पर sync() से बचें — यह गारंटीड डेडलॉक है। अधिक पठनीय एसिंक्रोनस कोड के लिए MainActor के माध्यम से मुख्य थ्रेड पर स्वचालित वापसी के साथ async/await (Swift 5.5+) का उपयोग करें।

UI थ्रेड में synchronized से बचना

मुख्य थ्रेड पर Kotlin में synchronized ब्लॉक और Swift में @synchronized खतरनाक हैं: यदि किसी अन्य थ्रेड ने पहले ही यह लॉक प्राप्त कर लिया है, तो मुख्य थ्रेड प्रतीक्षा में फ़्रीज़ हो जाएगा। लॉक के बजाय एटॉमिक प्रकार (AtomicInteger, Swift में एटॉमिक प्रॉपर्टी) या सीरियल क्यू का उपयोग करें।

Android पर कोरूटीन के साथ एसिंक्रोनस डेटा लोडिंग का उदाहरण:

kotlin
class DataViewModel : ViewModel() {
    private val _data = MutableStateFlow<List<Item>>(emptyList())
    val data: StateFlow<List<Item>> = _data.asStateFlow()

    fun loadData() {
        viewModelScope.launch(Dispatchers.IO) {
            val result = fetchFromNetwork()
            _data.emit(result)
        }
    }
}

डेवलपमेंट चरण में फ़्रीज़ की रोकथाम

उपकरणों, आर्किटेक्चर सिद्धांतों और कोड रिव्यू प्रक्रियाओं का संयोजन व्यवस्थित रूप से फ़्रीज़ को रोकने में मदद करता है।

penaltyDeath के साथ StrictMode

थ्रेड पॉलिसियों के लिए StrictMode को penaltyDeath के साथ कॉन्फ़िगर करें — इससे मुख्य थ्रेड पर नेटवर्क कॉल या डिस्क I/O डिटेक्ट होने पर तत्काल ऐप क्रैश हो जाएगा। डेवलपर समस्या को अनदेखा नहीं कर सकता। प्रोडक्शन बिल्ड में, बिना क्रैश के आँकड़े इकट्ठा करने के लिए penaltyLog का उपयोग करें।

Debug स्कीम में Main Thread Checker

iOS पर, Debug स्कीम में Main Thread Checker सक्षम करें और CI को इस विकल्प के साथ टेस्ट चलाने के लिए कॉन्फ़िगर करें। यदि किसी टेस्ट में बैकग्राउंड थ्रेड से UIKit कॉल है — तो उसे फेल होना चाहिए। TestFlight पर भेजने से पहले समस्या की पहचान करने का यह एकमात्र विश्वसनीय तरीका है।

मल्टीथ्रेडिंग जाँच के साथ पीयर रिव्यू

कोड रिव्यू प्रक्रिया में एक अनिवार्य बिंदु जोड़ें: जाँच करें कि कोई भी नेटवर्क कॉल, फ़ाइल ऑपरेशन, डेटाबेस एक्सेस या भारी गणना बैकग्राउंड थ्रेड पर चलती है। डेडलॉक को स्थैतिक विश्लेषकों से डिटेक्ट किया जा सकता है: Facebook का Infer और Xcode का Thread Safety Checker रनटाइम से पहले संभावित लॉक ढूँढते हैं।

  • Android — StrictMode, Infer, Android Lint Multithread, viewModelScope के साथ Kotlin Coroutines
  • iOS — Main Thread Checker, TSAN (Thread Sanitizer), Xcode Analyze, MainActor के साथ Swift async/await
  • क्रॉस-प्लेटफ़ॉर्म — Flutter compute isolate, requestAnimationFrame के साथ React Native interaction manager

अक्सर पूछे जाने वाले प्रश्न

फ़्रीज़ और ANR में क्या अंतर है?

ANR (Application Not Responding) एक Android सिस्टम सूचना है जो मुख्य थ्रेड के 5 सेकंड से अधिक फ़्रीज़ होने पर प्रकट होती है। फ़्रीज़ एक व्यापक अवधारणा है: किसी भी अवधि का कोई भी UI ब्लॉकेज। iOS में ANR नहीं है, लेकिन 10–20 सेकंड टाइमआउट वाला Watchdog है।

Android पर traces.txt कैसे पढ़ें?

फ़ाइल /data/anr/traces.txt पर स्थित है। एक्सेस के लिए रूट एक्सेस या adb shell चाहिए: रूट अधिकारों के साथ adb shell cat /data/anr/traces.txt \> traces.txt चलाएँ। स्टैक में “main” थ्रेड खोजें — अंतिम कॉल की गई विधि ब्लॉकेज का कारण बताती है।

iOS पर ऐप फ़्रीज़ क्यों होता है लेकिन क्रैश नहीं?

यदि फ़्रीज़ 10 सेकंड से कम रहता है, तो Watchdog ट्रिगर नहीं होता, और ऐप बस ब्लॉकिंग ऑपरेशन पूरा होने तक “फँसा” रहता है। उपयोगकर्ता को क्रैश नहीं दिखता लेकिन निराशा होती है। ऐसे मामलों का पता लगाने के लिए, कस्टम निष्पादन समय ट्रेस के साथ MetricKit का उपयोग करें।

फ़्रीज़ के लिए ऐप का परीक्षण कैसे करें?

UI परीक्षण का उपयोग करें जाँच के साथ कि स्क्रीन < 1 सेकंड में खुलती है। टैप और अगली स्क्रीन की उपस्थिति के बीच समय माप को CI में जोड़ें। Android पर, एसिंक्रोनस ऑपरेशन की प्रतीक्षा के लिए IdlingResource के साथ Espresso का उपयोग करें। iOS पर, लोडिंग समय जाँचने के लिए XCTWaiter के साथ XCTest का उपयोग करें।

क्या SwiftUI फ़्रीज़ का कारण बन सकता है?

SwiftUI स्वयं फ़्रीज़ का कारण नहीं बनता, लेकिन body प्रॉपर्टी में जटिल गणनाएँ करती हैं। यदि भारी ऑपरेशन के कारण body की गणना में 500 ms लगते हैं, तो UI फ़्रीज़ हो जाता है। समाधान है गणनाओं को Task.detached में ले जाना और मुख्य एक्टर पर @State को एसिंक्रोनस रूप से अपडेट करना।

सारांश

  • फ़्रीज़ — सेकंड से दसियों सेकंड तक UI का पूर्ण ब्लॉकेज, जो मुख्य थ्रेड ब्लॉक, डेडलॉक या अनंत लूप के कारण होता है
  • निदान — Android पर /data/anr/traces.txt, iOS पर Stackshot और Main Thread Checker
  • मुख्य कारण — सिंक्रोनस I/O, थ्रेड्स के बीच डेडलॉक, अनंत रिकर्शन, लंबा GC
  • समाधान — सही डिस्पैचर्स के साथ कोरूटीन, MainActor के साथ async/await, I/O ऑपरेशन को बैकग्राउंड थ्रेड्स पर ले जाना
  • रोकथाम — penaltyDeath के साथ StrictMode, Main Thread Checker, डेडलॉक के लिए स्थैतिक विश्लेषण (Infer, TSAN)
  • Android पर फ़्रीज़ > 5 s = ANR; iOS पर > 10–20 s = Watchdog क्रैश (0x8badf00d)
  • अनुशंसा: Debug स्कीम में Thread Sanitizer सक्षम करें और CI को data race और डेडलॉक का पता लगाने के लिए TSAN के साथ परीक्षण चलाने हेतु कॉन्फ़िगर करें

हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे

IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।

परियोजना पर चर्चा करें

यह भी पढ़ें