यूज़र इंटरफ़ेस (यूआई) रेंडरिंग का मतलब है, आपके ऐप्लिकेशन से कोई फ़्रेम जनरेट करना और उसे स्क्रीन पर दिखाना. यह पक्का करने के लिए कि उपयोगकर्ता को आपके ऐप्लिकेशन के साथ इंटरैक्ट करने में कोई परेशानी न हो, आपके ऐप्लिकेशन को 60 फ़्रेम प्रति सेकंड (एफ़पीएस) की दर से फ़्रेम रेंडर करने चाहिए. इसके लिए, हर फ़्रेम को 16 मि॰से॰ से कम समय में रेंडर करना ज़रूरी है. यह समझने के लिए कि 60 फ़्रेम प्रति सेकंड को क्यों प्राथमिकता दी जाती है, Android परफ़ॉर्मेंस पैटर्न: 60 फ़्रेम प्रति सेकंड क्यों? लेख पढ़ें. अगर आपको 90 fps का इस्तेमाल करना है, तो यह विंडो 11 मि॰से॰ तक कम हो जाती है. वहीं, 120 fps के लिए यह 8 मि॰से॰ होती है.
अगर इस विंडो में 1 मि॰से॰ से ज़्यादा समय लगता है, तो इसका मतलब यह नहीं है कि फ़्रेम को 1 मि॰से॰ की देरी से दिखाया गया है. बल्कि, इसका मतलब है कि Choreographer फ़्रेम को पूरी तरह से हटा देता है. अगर आपके ऐप्लिकेशन में यूज़र इंटरफ़ेस (यूआई) की रेंडरिंग धीमी है, तो सिस्टम को फ़्रेम छोड़ने के लिए मजबूर किया जाता है. इससे उपयोगकर्ता को आपके ऐप्लिकेशन में स्टटरिंग (बहुत धीमी रेंडरिंग) का अनुभव होता है. इसे जैंक कहा जाता है. इस पेज पर, जंक का पता लगाने और उसे ठीक करने का तरीका बताया गया है.
अगर ऐसे गेम डेवलप किए जा रहे हैं जिनमें View सिस्टम का इस्तेमाल नहीं किया जाता, तो Choreographer को बायपास कर दिया जाता है. इस मामले में, फ़्रेम पेसिंग लाइब्रेरी, OpenGL और Vulkan गेम को Android पर आसानी से रेंडर करने और सही फ़्रेम पेसिंग हासिल करने में मदद करती है.
जैंक की पहचान करना
आपके ऐप्लिकेशन में, जंक की समस्या पैदा करने वाले कोड का पता लगाना मुश्किल हो सकता है. इस सेक्शन में, जंक की पहचान करने के तीन तरीकों के बारे में बताया गया है:
विज़ुअल जांच की मदद से, कुछ ही मिनटों में अपने ऐप्लिकेशन के सभी इस्तेमाल के उदाहरणों की जांच की जा सकती है. हालांकि, इसमें Systrace की तरह ज़्यादा जानकारी नहीं मिलती. Systrace से ज़्यादा जानकारी मिलती है. हालांकि, अगर आपने अपने ऐप्लिकेशन के सभी इस्तेमाल के उदाहरणों के लिए Systrace चलाया है, तो आपको इतना डेटा मिल सकता है कि उसका विश्लेषण करना मुश्किल हो सकता है. विज़ुअल जांच और Systrace, दोनों ही आपके लोकल डिवाइस पर जंक का पता लगाते हैं. अगर आपको लोकल डिवाइसों पर जंक नहीं दिखता है, तो परफ़ॉर्मेंस की कस्टम मॉनिटरिंग की सुविधा का इस्तेमाल करें. इससे, फ़ील्ड में चल रहे डिवाइसों पर अपने ऐप्लिकेशन के कुछ हिस्सों की परफ़ॉर्मेंस को मेज़र किया जा सकता है.
विज़ुअल जांच
विज़ुअल इंस्पेक्शन की मदद से, आपको उन इस्तेमाल के उदाहरणों का पता लगाने में मदद मिलती है जिनकी वजह से जंक फ़्रेम जनरेट हो रहे हैं. विज़ुअल जांच करने के लिए, अपना ऐप्लिकेशन खोलें और मैन्युअल तरीके से ऐप्लिकेशन के अलग-अलग हिस्सों को देखें. साथ ही, अपने यूज़र इंटरफ़ेस (यूआई) में जंक ढूंढें.
यहां विज़ुअल जांच करने के लिए कुछ सुझाव दिए गए हैं:
- अपने ऐप्लिकेशन का रिलीज़ किया गया वर्शन या कम से कम ऐसा वर्शन चलाएं जिसे डीबग न किया जा सके. ART रनटाइम, डीबग करने की सुविधाओं के साथ काम करने के लिए कई अहम ऑप्टिमाइज़ेशन बंद कर देता है. इसलिए, पक्का करें कि आपको वही दिख रहा हो जो किसी उपयोगकर्ता को दिखता है.
- प्रोफ़ाइल जीपीयू रेंडरिंग चालू करें. प्रोफ़ाइल जीपीयू रेंडरिंग, स्क्रीन पर बार दिखाती है. इससे आपको यह पता चलता है कि यूज़र इंटरफ़ेस (यूआई) विंडो के फ़्रेम को रेंडर करने में कितना समय लगता है. यह समय, हर फ़्रेम के लिए 16 मि॰से॰ के बेंचमार्क के हिसाब से होता है. हर बार में रंगीन कॉम्पोनेंट होते हैं. ये कॉम्पोनेंट, रेंडरिंग पाइपलाइन के किसी स्टेज से मैप होते हैं. इससे यह पता चलता है कि कौनसे हिस्से को रेंडर होने में सबसे ज़्यादा समय लग रहा है. उदाहरण के लिए, अगर फ़्रेम को इनपुट प्रोसेस करने में ज़्यादा समय लगता है, तो अपने ऐप्लिकेशन के उस कोड को देखें जो उपयोगकर्ता के इनपुट को प्रोसेस करता है.
- उन कॉम्पोनेंट की जांच करें जो जंक के सामान्य सोर्स होते हैं. जैसे,
RecyclerView. - ऐप्लिकेशन को कोल्ड स्टार्ट से लॉन्च करें.
- अपने ऐप्लिकेशन को किसी ऐसे डिवाइस पर चलाएं जो धीमा हो, ताकि समस्या और बढ़ जाए.
जब आपको ऐसे इस्तेमाल के उदाहरण मिलते हैं जिनसे जंक होता है, तो आपको इस बात का अंदाज़ा लग सकता है कि आपके ऐप्लिकेशन में जंक किस वजह से हो रहा है. अगर आपको ज़्यादा जानकारी चाहिए, तो वजह के बारे में ज़्यादा जानने के लिए, Systrace का इस्तेमाल करें.
Systrace
Systrace एक ऐसा टूल है जो यह दिखाता है कि पूरा डिवाइस क्या कर रहा है. हालांकि, यह आपके ऐप्लिकेशन में जंक की पहचान करने के लिए काम का हो सकता है. Systrace में सिस्टम ओवरहेड कम होता है. इसलिए, इंस्ट्रुमेंटेशन के दौरान आपको असली जंक का अनुभव मिल सकता है.
अपने डिवाइस पर, परफ़ॉर्मेंस से जुड़ी समस्या को ठीक करने के लिए, Systrace की मदद से ट्रेस रिकॉर्ड करें. Systrace का इस्तेमाल करने के तरीके के बारे में जानने के लिए, कमांड लाइन पर सिस्टम ट्रेस कैप्चर करना लेख पढ़ें. Systrace को प्रोसेस और थ्रेड के हिसाब से बांटा जाता है. Systrace में अपने ऐप्लिकेशन की प्रोसेस ढूंढें. यह कुछ इस तरह दिखती है पहली इमेज.
पहली इमेज में दिए गए Systrace के उदाहरण में, जंक का पता लगाने के लिए यह जानकारी शामिल है:
- Systrace से पता चलता है कि हर फ़्रेम कब बनाया गया था. साथ ही, यह हर फ़्रेम को कलर कोड करता है, ताकि रेंडर होने में लगने वाले ज़्यादा समय को हाइलाइट किया जा सके. इससे आपको विज़ुअल की जांच करने की तुलना में, एक-एक जंकी फ़्रेम का ज़्यादा सटीक तरीके से पता लगाने में मदद मिलती है. ज़्यादा जानकारी के लिए, यूज़र इंटरफ़ेस (यूआई) फ़्रेम और सूचनाओं की जांच करना लेख पढ़ें.
- Systrace, आपके ऐप्लिकेशन में मौजूद समस्याओं का पता लगाता है. साथ ही, अलग-अलग फ़्रेम और सूचनाएं पैनल, दोनों में सूचनाएं दिखाता है. सूचना में दिए गए निर्देशों का पालन करना सबसे सही है.
- Android फ़्रेमवर्क और लाइब्रेरी के कुछ हिस्सों में, ट्रेस मार्कर होते हैं. जैसे,
RecyclerView. इसलिए, systrace टाइमलाइन से पता चलता है कि यूज़र इंटरफ़ेस (यूआई) थ्रेड पर ये तरीके कब लागू किए जाते हैं और इन्हें लागू होने में कितना समय लगता है.
Systrace आउटपुट देखने के बाद, हो सकता है कि आपको अपने ऐप्लिकेशन में ऐसे तरीके दिखें जिनकी वजह से आपको लगता है कि जंक हो रहा है. उदाहरण के लिए, अगर टाइमलाइन से पता चलता है कि RecyclerView में ज़्यादा समय लगने की वजह से फ़्रेम धीरे-धीरे रेंडर हो रहा है, तो ज़्यादा जानकारी पाने के लिए, कस्टम ट्रेस इवेंट जोड़ें और Systrace को फिर से चलाएं. नए Systrace में, टाइमलाइन से पता चलता है कि आपके ऐप्लिकेशन के तरीकों को कब कॉल किया जाता है और उन्हें पूरा होने में कितना समय लगता है.
अगर Systrace से यह पता नहीं चलता कि यूज़र इंटरफ़ेस (यूआई) थ्रेड को पूरा होने में इतना समय क्यों लग रहा है, तो Android CPU Profiler का इस्तेमाल करके, सैंपल या इंस्ट्रुमेंट की गई मेथड ट्रेस रिकॉर्ड करें. आम तौर पर, जंक का पता लगाने के लिए, मेथड ट्रेसिंग का इस्तेमाल करना सही नहीं होता. ऐसा इसलिए, क्योंकि इससे ज़्यादा ओवरहेड की वजह से, फ़ॉल्स-पॉज़िटिव जंक मिलते हैं. साथ ही, इससे यह भी पता नहीं चलता कि थ्रेड कब चल रही हैं और कब ब्लॉक की गई हैं. हालांकि, मेथड ट्रेस की मदद से, अपने ऐप्लिकेशन में उन तरीकों की पहचान की जा सकती है जिनमें सबसे ज़्यादा समय लग रहा है. इन तरीकों की पहचान करने के बाद, ट्रेस मार्कर जोड़ें और Systrace को फिर से चलाएं. इससे यह पता चलेगा कि क्या इन तरीकों की वजह से जंक हो रहा है.
ज़्यादा जानकारी के लिए, Systrace के बारे में जानकारी लेख पढ़ें.
परफ़ॉर्मेंस मॉनिटर करने की कस्टम सुविधा
अगर आपको किसी लोकल डिवाइस पर जंक नहीं दिखता है, तो अपने ऐप्लिकेशन में परफ़ॉर्मेंस मॉनिटरिंग की कस्टम सुविधा बनाएं. इससे फ़ील्ड में मौजूद डिवाइसों पर जंक के सोर्स का पता लगाने में मदद मिलेगी.
इसके लिए, अपने ऐप्लिकेशन के कुछ हिस्सों से फ़्रेम रेंडर होने में लगने वाला समय इकट्ठा करें. इसके लिए, FrameMetricsAggregator का इस्तेमाल करें. साथ ही, Firebase Performance Monitoring का इस्तेमाल करके डेटा रिकॉर्ड करें और उसका विश्लेषण करें.
ज़्यादा जानने के लिए, Android के लिए परफ़ॉर्मेंस मॉनिटरिंग का इस्तेमाल शुरू करना लेख पढ़ें.
रुकी हुई फ़्रेम
फ़्रोज़न फ़्रेम, यूज़र इंटरफ़ेस (यूआई) फ़्रेम होते हैं. इन्हें रेंडर होने में 700 मि॰से॰ से ज़्यादा समय लगता है. यह एक समस्या है, क्योंकि फ़्रेम रेंडर होने के दौरान, आपका ऐप्लिकेशन लगभग एक सेकंड तक काम नहीं करता है. साथ ही, यह उपयोगकर्ता के इनपुट पर कोई जवाब नहीं देता. हमारा सुझाव है कि ऐप्लिकेशन को ऑप्टिमाइज़ किया जाए, ताकि यूज़र इंटरफ़ेस (यूआई) को बेहतर बनाया जा सके. इसके लिए, 16 मिलीसेकंड के अंदर फ़्रेम रेंडर करना ज़रूरी है. हालांकि, ऐप्लिकेशन चालू होने के दौरान या किसी दूसरी स्क्रीन पर ट्रांज़िशन करते समय, शुरुआती फ़्रेम को रेंडर होने में 16 मि॰से॰ से ज़्यादा समय लग सकता है. ऐसा इसलिए, क्योंकि आपके ऐप्लिकेशन को व्यू बढ़ाने, स्क्रीन को लेआउट करने, और शुरुआती ड्रॉ को स्क्रैच से पूरा करने की ज़रूरत होती है. इसलिए, Android रुके हुए फ़्रेम को, धीमी रेंडरिंग से अलग ट्रैक करता है. आपके ऐप्लिकेशन में किसी भी फ़्रेम को रेंडर होने में 700 मि॰से॰ से ज़्यादा समय नहीं लगना चाहिए.
फ़्रीज़ किए गए फ़्रेम, धीमी रेंडरिंग का एक चरम रूप है. इसलिए, समस्या का पता लगाने और उसे ठीक करने की प्रोसेस एक जैसी होती है.
जैंक को ट्रैक करना
Perfetto में मौजूद FrameTimeline की मदद से, धीरे-धीरे चलने वाले या फ़्रीज़ हो चुके फ़्रेम को ट्रैक किया जा सकता है.
रेंडर करने में ज़्यादा समय लेने वाले फ़्रेम, रुके हुए फ़्रेम, और एएनआर के बीच संबंध
धीमे फ़्रेम, फ़्रीज़ फ़्रेम, और एएनआर, ये सभी जंक के अलग-अलग रूप हैं. ये आपके ऐप्लिकेशन में दिख सकते हैं. इनके बीच का अंतर समझने के लिए, यहां दी गई टेबल देखें.
| रेंडर करने में ज़्यादा समय लेने वाले फ़्रेम | रुकी हुई फ़्रेम | ANRs | |
|---|---|---|---|
| रेंडर होने में लगने वाला समय | 16 से 700 मि॰से॰ के बीच | 700 मि॰से॰ से 5 सेकंड के बीच | पांच सेकंड से ज़्यादा |
| उपयोगकर्ता पर असर डालने वाला इलाका |
|
|
|
रेंडर करने में ज़्यादा समय लेने वाले फ़्रेम और रुके हुए फ़्रेम को अलग-अलग ट्रैक करना
ऐप्लिकेशन चालू होने के दौरान या किसी दूसरी स्क्रीन पर ट्रांज़िशन करते समय, शुरुआती फ़्रेम को रेंडर होने में 16 मि॰से॰ से ज़्यादा समय लग सकता है. ऐसा इसलिए होता है, क्योंकि ऐप्लिकेशन को व्यू बढ़ाने होते हैं, स्क्रीन को लेआउट करना होता है, और शुरुआती ड्रॉ को स्क्रैच से पूरा करना होता है.
जंक को प्राथमिकता देने और उसे ठीक करने के सबसे सही तरीके
अपने ऐप्लिकेशन में जंक की समस्या को ठीक करने के लिए, इन सबसे सही तरीकों को ध्यान में रखें:
- जंक के ऐसे इंस्टेंस का पता लगाना और उन्हें ठीक करना जिन्हें आसानी से दोहराया जा सकता है.
- एएनआर को प्राथमिकता दें. फ़्रेम के धीमे होने या रुक जाने से, ऐप्लिकेशन धीमा लग सकता है. हालांकि, एएनआर की वजह से ऐप्लिकेशन काम करना बंद कर देता है.
- धीमी रेंडरिंग की समस्या को दोहराना मुश्किल है. हालांकि, 700 मि॰से॰ तक फ़्रीज़ हुए फ़्रेम को हटाकर, इसकी शुरुआत की जा सकती है. ऐसा आम तौर पर तब होता है, जब ऐप्लिकेशन शुरू हो रहा हो या स्क्रीन बदल रही हो.
जैंक की समस्या ठीक करना
जंक को ठीक करने के लिए, देखें कि कौनसे फ़्रेम 16 मि॰से॰ में पूरे नहीं हो रहे हैं और देखें कि क्या गलत है. देखें कि क्या कुछ फ़्रेम में Record View#draw या Layout को सामान्य से ज़्यादा समय लग रहा है. इन समस्याओं और अन्य समस्याओं के लिए, जंक के सामान्य सोर्स देखें.
जंक से बचने के लिए, लंबे समय तक चलने वाले टास्क को यूज़र इंटरफ़ेस (यूआई) थ्रेड से बाहर एसिंक्रोनस तरीके से चलाएं. हमेशा इस बात का ध्यान रखें कि आपका कोड किस थ्रेड पर चल रहा है. साथ ही, मुख्य थ्रेड पर गैर-ज़रूरी टास्क पोस्ट करते समय सावधानी बरतें.
अगर आपके ऐप्लिकेशन के लिए कोई जटिल और अहम प्राइमरी यूज़र इंटरफ़ेस (यूआई) है, जैसे कि स्क्रोल करने वाली सेंट्रल लिस्ट, तो इंस्ट्रुमेंटेशन टेस्ट लिखें. ये टेस्ट, रेंडर होने में लगने वाले ज़्यादा समय का अपने-आप पता लगा सकते हैं. साथ ही, रिग्रेशन को रोकने के लिए, बार-बार टेस्ट चला सकते हैं.
जंक की सामान्य वजहें
यहां दिए गए सेक्शन में, View
सिस्टम का इस्तेमाल करने वाले ऐप्लिकेशन में जंक के सामान्य सोर्स के बारे में बताया गया है. साथ ही, उन्हें ठीक करने के सबसे सही तरीके बताए गए हैं. Jetpack Compose में परफ़ॉर्मेंस से जुड़ी समस्याओं को ठीक करने के बारे में जानकारी पाने के लिए, Jetpack Compose की परफ़ॉर्मेंस देखें.
स्क्रोल की जा सकने वाली सूचियां
ListView और खास तौर पर RecyclerView का इस्तेमाल, आम तौर पर स्क्रोल करने वाली उन जटिल सूचियों के लिए किया जाता है जिनमें जंक होने की आशंका सबसे ज़्यादा होती है. इन दोनों में Systrace मार्कर होते हैं. इसलिए, Systrace का इस्तेमाल करके यह देखा जा सकता है कि ये आपके ऐप्लिकेशन में जंक का कारण बन रहे हैं या नहीं. RecyclerView में ट्रेस सेक्शन पाने के लिए, कमांड-लाइन आर्ग्युमेंट -a
<your-package-name> पास करें. साथ ही, आपके जोड़े गए किसी भी ट्रेस मार्कर को दिखाएं. अगर उपलब्ध हो, तो Systrace आउटपुट में जनरेट हुई सूचनाओं में दिए गए निर्देशों का पालन करें. Systrace में, RecyclerView-ट्रेस किए गए सेक्शन पर क्लिक करके, RecyclerView के काम करने के तरीके के बारे में जानकारी देखी जा सकती है.
RecyclerView: notifyDataSetChanged()
अगर आपको अपने RecyclerView में मौजूद हर आइटम को फिर से बाउंड होते हुए दिखता है, तो इसका मतलब है कि उन्हें एक फ़्रेम में फिर से लेआउट किया गया है और फिर से बनाया गया है. ऐसे में, पक्का करें कि आपने छोटे अपडेट के लिए notifyDataSetChanged(), setAdapter(Adapter) या swapAdapter(Adapter,
boolean) को कॉल न किया हो. इन तरीकों से पता चलता है कि पूरी सूची के कॉन्टेंट में बदलाव हुए हैं. ये सिस्ट्रेस में RV FullInvalidate के तौर पर दिखते हैं. इसके बजाय, कॉन्टेंट में बदलाव होने या नया कॉन्टेंट जोड़े जाने पर, कम से कम अपडेट जनरेट करने के लिए SortedList या DiffUtil का इस्तेमाल करें.
उदाहरण के लिए, मान लें कि किसी ऐप्लिकेशन को सर्वर से खबरों की सूची का नया वर्शन मिलता है. इस जानकारी को अडैप्टर पर पोस्ट करने पर, notifyDataSetChanged() को कॉल किया जा सकता है. इसका उदाहरण यहां दिया गया है:
Kotlin
fun onNewDataArrived(news: List<News>) { myAdapter.news = news myAdapter.notifyDataSetChanged() }
Java
void onNewDataArrived(List<News> news) { myAdapter.setNews(news); myAdapter.notifyDataSetChanged(); }
हालांकि, इसमें एक समस्या यह है कि अगर कोई मामूली बदलाव होता है, जैसे कि सबसे ऊपर कोई एक आइटम जोड़ा जाता है, तो RecyclerView को इसकी जानकारी नहीं मिलती. इसलिए, इसे कैश मेमोरी में सेव किए गए आइटम की पूरी स्थिति को हटाने के लिए कहा जाता है. इसलिए, इसे हर चीज़ को फिर से बाइंड करना होगा.
हमारा सुझाव है कि आप DiffUtil का इस्तेमाल करें. यह आपके लिए कम से कम अपडेट का हिसाब लगाता है और उन्हें भेजता है:
Kotlin
fun onNewDataArrived(news: List<News>) { val oldNews = myAdapter.items val result = DiffUtil.calculateDiff(MyCallback(oldNews, news)) myAdapter.news = news result.dispatchUpdatesTo(myAdapter) }
Java
void onNewDataArrived(List<News> news) { List<News> oldNews = myAdapter.getItems(); DiffResult result = DiffUtil.calculateDiff(new MyCallback(oldNews, news)); myAdapter.setNews(news); result.dispatchUpdatesTo(myAdapter); }
DiffUtil को यह बताने के लिए कि आपकी सूचियों की जांच कैसे की जाए, MyCallback को Callback के तौर पर लागू करें.
RecyclerView: नेस्ट किए गए RecyclerView
RecyclerView के कई इंस्टेंस को नेस्ट करना आम बात है. खास तौर पर, हॉरिज़ॉन्टल तौर पर स्क्रोल की जा सकने वाली सूचियों की वर्टिकल सूची के साथ ऐसा होता है. इसका एक उदाहरण, Play Store के मुख्य पेज पर मौजूद ऐप्लिकेशन की ग्रिड हैं. यह तरीका बहुत अच्छा है, लेकिन इसमें कई व्यू एक साथ दिखते हैं.
अगर आपको पेज पर पहली बार नीचे की ओर स्क्रोल करने पर, कई इनर आइटम दिखते हैं, तो आपको यह देखना चाहिए कि RecyclerView के इनर (हॉरिज़ॉन्टल) इंस्टेंस के बीच RecyclerView.RecycledViewPool शेयर किया जा रहा है या नहीं. डिफ़ॉल्ट रूप से, हर RecyclerView के पास आइटम का अपना पूल होता है. हालांकि, अगर स्क्रीन पर एक साथ कई itemViews दिख रहे हैं और सभी लाइनों में एक जैसे व्यू दिख रहे हैं, तो अलग-अलग हॉरिज़ॉन्टल सूचियों में itemViews शेयर न किए जा सकने पर समस्या होती है.
Kotlin
class OuterAdapter : RecyclerView.Adapter<OuterAdapter.ViewHolder>() { ... override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { // Inflate inner item, find innerRecyclerView by ID. val innerLLM = LinearLayoutManager(parent.context, LinearLayoutManager.HORIZONTAL, false) innerRv.apply { layoutManager = innerLLM recycledViewPool = sharedPool } return OuterAdapter.ViewHolder(innerRv) } ...
Java
class OuterAdapter extends RecyclerView.Adapter<OuterAdapter.ViewHolder> { RecyclerView.RecycledViewPool sharedPool = new RecyclerView.RecycledViewPool(); ... @Override public void onCreateViewHolder(ViewGroup parent, int viewType) { // Inflate inner item, find innerRecyclerView by ID. LinearLayoutManager innerLLM = new LinearLayoutManager(parent.getContext(), LinearLayoutManager.HORIZONTAL); innerRv.setLayoutManager(innerLLM); innerRv.setRecycledViewPool(sharedPool); return new OuterAdapter.ViewHolder(innerRv); } ...
अगर आपको और ऑप्टिमाइज़ करना है, तो RecyclerView के LinearLayoutManager पर setInitialPrefetchItemCount(int) को कॉल करें. उदाहरण के लिए, अगर आपको एक लाइन में हमेशा 3.5 आइटम दिखते हैं, तो innerLLM.setInitialItemPrefetchCount(4) को कॉल करें. इससे RecyclerView को यह सिग्नल मिलता है कि जब कोई हॉरिज़ॉन्टल लाइन स्क्रीन पर आने वाली हो, तो उसे यूज़र इंटरफ़ेस (यूआई) थ्रेड पर बचे हुए समय में, उस लाइन में मौजूद आइटम को पहले से फ़ेच करने की कोशिश करनी चाहिए.
RecyclerView: बहुत ज़्यादा इन्फ़्लेशन या क्रिएट होने में बहुत ज़्यादा समय लग रहा है
ज़्यादातर मामलों में, RecyclerView में मौजूद प्रीफ़ेच सुविधा, महंगाई की वजह से होने वाले नुकसान को कम करने में मदद कर सकती है. ऐसा इसलिए, क्योंकि यह सुविधा यूज़र इंटरफ़ेस (यूआई) थ्रेड के निष्क्रिय होने पर, पहले से ही काम कर लेती है.
अगर आपको किसी फ़्रेम के दौरान इन्फ़्लेशन दिख रहा है और RV
Prefetch लेबल वाले सेक्शन में नहीं दिख रहा है, तो पक्का करें कि आप ऐसे डिवाइस पर टेस्टिंग कर रहे हों जिस पर यह सुविधा काम करती है. साथ ही, सपोर्ट लाइब्रेरी के नए वर्शन का इस्तेमाल कर रहे हों.
प्रीफ़ेचिंग की सुविधा, सिर्फ़ Android 5.0 API लेवल 21 और इसके बाद के वर्शन पर काम करती है.
अगर आपको स्क्रीन पर नए आइटम आने पर, अक्सर जंक की वजह से इन्फ़्लेशन दिखता है, तो पुष्टि करें कि आपके पास ज़रूरत से ज़्यादा व्यू टाइप न हों. RecyclerView के कॉन्टेंट में व्यू टाइप जितने कम होंगे, स्क्रीन पर नए आइटम टाइप आने पर उन्हें उतना ही कम बड़ा करना होगा. अगर हो सके, तो व्यू टाइप को एक साथ मर्ज करें. अगर टाइप के बीच सिर्फ़ आइकॉन, रंग या टेक्स्ट में बदलाव होता है, तो बाइंड करने के समय उस बदलाव को किया जा सकता है. इससे इन्फ्लेशन से बचा जा सकता है. साथ ही, इससे आपके ऐप्लिकेशन की मेमोरी का इस्तेमाल कम हो जाता है.
अगर व्यू टाइप सही दिख रहे हैं, तो महंगाई की वजह से होने वाली लागत को कम करने पर ध्यान दें.
ग़ैरज़रूरी कंटेनर और स्ट्रक्चरल व्यू कम करने से मदद मिल सकती है. itemViews को ConstraintLayout के साथ बनाएं. इससे स्ट्रक्चरल व्यू कम करने में मदद मिल सकती है.
अगर आपको परफ़ॉर्मेंस को और बेहतर बनाना है और आपके आइटम के क्रम आसान हैं, साथ ही आपको थीम और स्टाइल से जुड़ी जटिल सुविधाओं की ज़रूरत नहीं है, तो कंस्ट्रक्टर को खुद कॉल करें. हालांकि, अक्सर ऐसा होता है कि XML की सुविधाओं और इसे इस्तेमाल करने में आसानी को खोना, इसके बदले में मिलने वाले फ़ायदों के लायक नहीं होता.
RecyclerView: Bind में बहुत ज़्यादा समय लग रहा है
बाइंडिंग—यानी कि onBindViewHolder(VH,
int)— आसान होनी चाहिए. साथ ही, सबसे जटिल आइटम को छोड़कर बाकी सभी आइटम के लिए, इसमें एक मिलीसेकंड से भी कम समय लगना चाहिए. इसे आपके अडैप्टर के इंटरनल आइटम डेटा से, प्लेन ओल्ड Java ऑब्जेक्ट (POJO) आइटम लेने चाहिए. साथ ही, ViewHolder में व्यू पर सेटर को कॉल करना चाहिए. अगर RV OnBindView में ज़्यादा समय लग रहा है, तो पुष्टि करें कि आपने बाइंड कोड में कम से कम काम किया हो.
अगर अडैप्टर में डेटा सेव करने के लिए, बेसिक POJO ऑब्जेक्ट का इस्तेमाल किया जा रहा है, तो onBindViewHolder में बाइंडिंग कोड लिखने से पूरी तरह बचा जा सकता है. इसके लिए, डेटा बाइंडिंग लाइब्रेरी का इस्तेमाल करें.
RecyclerView या ListView: लेआउट या ड्रॉ करने में बहुत ज़्यादा समय लग रहा है
ड्रॉ और लेआउट से जुड़ी समस्याओं के लिए, लेआउट की परफ़ॉर्मेंस और रेंडरिंग की परफ़ॉर्मेंस सेक्शन देखें.
ListView: महंगाई
अगर आपने सावधानी नहीं बरती, तो आपसे गलती से ListView में रीसाइक्लिंग की सुविधा बंद हो सकती है. अगर आपको स्क्रीन पर हर बार कोई आइटम दिखने पर, व्यू में बढ़ोतरी दिखती है, तो पक्का करें कि Adapter.getView() को लागू करने के दौरान, convertView पैरामीटर को म्यूट, री-बाइंड, और वापस किया जा रहा हो. अगर आपके getView() का इस्तेमाल हमेशा बढ़ता रहता है, तो आपके ऐप्लिकेशन को ListView में रीसाइक्लिंग के फ़ायदे नहीं मिलते. आपके getView() का स्ट्रक्चर, यहां दिए गए स्ट्रक्चर के जैसा होना चाहिए:
Kotlin
fun getView(position: Int, convertView: View?, parent: ViewGroup): View { return (convertView ?: layoutInflater.inflate(R.layout.my_layout, parent, false)).apply { // Bind content from position to convertView. } }
Java
View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { // Only inflate if no convertView passed. convertView = layoutInflater.inflate(R.layout.my_layout, parent, false) } // Bind content from position to convertView. return convertView; }
लेआउट की परफ़ॉर्मेंस
अगर Systrace से पता चलता है कि Choreographer#doFrame का Layout सेगमेंट बहुत ज़्यादा या बार-बार काम कर रहा है, तो इसका मतलब है कि आपको लेआउट की परफ़ॉर्मेंस से जुड़ी समस्याएं आ रही हैं. आपके ऐप्लिकेशन के लेआउट की परफ़ॉर्मेंस इस बात पर निर्भर करती है कि व्यू हैरारकी के किस हिस्से में लेआउट पैरामीटर या इनपुट बदल रहे हैं.
लेआउट की परफ़ॉर्मेंस: लागत
अगर सेगमेंट कुछ मिलीसेकंड से ज़्यादा समय लेते हैं, तो ऐसा हो सकता है कि आपको RelativeLayouts या weighted-LinearLayouts के लिए नेस्टिंग की सबसे खराब परफ़ॉर्मेंस मिल रही हो. इनमें से हर लेआउट, अपने चाइल्ड लेआउट के लिए कई मेज़र और लेआउट पास ट्रिगर कर सकता है. इसलिए, इन्हें नेस्ट करने से नेस्टिंग की डेप्थ पर O(n^2) व्यवहार हो सकता है.
RelativeLayout या LinearLayout की वज़न की सुविधा का इस्तेमाल, सिर्फ़ सबसे निचले लीफ़ नोड को छोड़कर, अन्य सभी नोड में न करें. ऐसा करने के लिए, ये तरीके अपनाएं:
- अपने स्ट्रक्चरल व्यू को फिर से व्यवस्थित करें.
- कस्टम लेआउट लॉजिक तय करें. किसी उदाहरण के लिए, लेआउट के क्रम को ऑप्टिमाइज़ करना लेख पढ़ें.
ConstraintLayoutमें बदलने की कोशिश करें. इसमें आपको मिलती-जुलती सुविधाएं मिलती हैं. साथ ही, परफ़ॉर्मेंस से जुड़ी समस्याएं भी नहीं होती हैं.
लेआउट की परफ़ॉर्मेंस: फ़्रीक्वेंसी
लेआउट तब होता है, जब स्क्रीन पर नया कॉन्टेंट दिखता है. उदाहरण के लिए, जब RecyclerView में कोई नया आइटम स्क्रोल करके दिखता है. अगर हर फ़्रेम पर लेआउट में बदलाव हो रहा है, तो हो सकता है कि लेआउट को ऐनिमेट किया जा रहा हो. इससे फ़्रेम ड्रॉप होने की समस्या हो सकती है.
आम तौर पर, ऐनिमेशन को View की ड्रॉइंग प्रॉपर्टी पर चलना चाहिए. जैसे, ये:
इन प्रॉपर्टी को लेआउट प्रॉपर्टी की तुलना में बहुत कम खर्च में बदला जा सकता है. जैसे, पैडिंग या मार्जिन. आम तौर पर, किसी व्यू की ड्रॉइंग प्रॉपर्टी बदलने के लिए, सेटर को कॉल करना ज़्यादा किफ़ायती होता है. इससे invalidate() ट्रिगर होता है. इसके बाद, अगले फ़्रेम में draw(Canvas) ट्रिगर होता है. यह फ़ंक्शन, उस व्यू के लिए ड्रॉइंग ऑपरेशन को फिर से रिकॉर्ड करता है जिसे अमान्य कर दिया गया है. साथ ही, यह आम तौर पर लेआउट से काफ़ी सस्ता होता है.
रेंडरिंग की परफ़ॉर्मेंस
Android का यूज़र इंटरफ़ेस (यूआई) दो चरणों में काम करता है:
- यूज़र इंटरफ़ेस (यूआई) थ्रेड पर Record View#draw, जो हर अमान्य व्यू पर
draw(Canvas)चलता है. यह कस्टम व्यू या आपके कोड में कॉल शुरू कर सकता है. RenderThreadपर DrawFrame, जो नेटिवRenderThreadपर चलता है, लेकिन Record View#draw फ़ेज़ से जनरेट हुए काम के आधार पर काम करता है.
रेंडरिंग परफ़ॉर्मेंस: यूज़र इंटरफ़ेस (यूआई) थ्रेड
अगर Record View#draw में ज़्यादा समय लग रहा है, तो आम तौर पर ऐसा तब होता है, जब यूज़र इंटरफ़ेस (यूआई) थ्रेड पर बिटमैप पेंट किया जा रहा हो. बिटमैप में पेंट करने के लिए, सीपीयू रेंडरिंग का इस्तेमाल किया जाता है. इसलिए, जब भी हो सके, इसका इस्तेमाल न करें. यह समस्या है या नहीं, यह देखने के लिए Android CPU Profiler के साथ मेथड ट्रेसिंग का इस्तेमाल किया जा सकता है.
किसी बिटमैप में पेंटिंग अक्सर तब की जाती है, जब कोई ऐप्लिकेशन उसे दिखाने से पहले सजाना चाहता है. कभी-कभी, सजावट में गोल कोनों को जोड़ना शामिल होता है:
Kotlin
val paint = Paint().apply { isAntiAlias = true } Canvas(roundedOutputBitmap).apply { // Draw a round rect to define the shape: drawRoundRect( 0f, 0f, roundedOutputBitmap.width.toFloat(), roundedOutputBitmap.height.toFloat(), 20f, 20f, paint ) paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.MULTIPLY) // Multiply content on top to make it rounded. drawBitmap(sourceBitmap, 0f, 0f, paint) setBitmap(null) // Now roundedOutputBitmap has sourceBitmap inside, but as a circle. }
Java
Canvas bitmapCanvas = new Canvas(roundedOutputBitmap); Paint paint = new Paint(); paint.setAntiAlias(true); // Draw a round rect to define the shape: bitmapCanvas.drawRoundRect(0, 0, roundedOutputBitmap.getWidth(), roundedOutputBitmap.getHeight(), 20, 20, paint); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY)); // Multiply content on top to make it rounded. bitmapCanvas.drawBitmap(sourceBitmap, 0, 0, paint); bitmapCanvas.setBitmap(null); // Now roundedOutputBitmap has sourceBitmap inside, but as a circle.
अगर यूज़र इंटरफ़ेस (यूआई) थ्रेड पर इस तरह का काम किया जा रहा है, तो इसे बैकग्राउंड में डीकोडिंग थ्रेड पर किया जा सकता है. कुछ मामलों में, जैसे कि ऊपर दिए गए उदाहरण में, ड्रॉ के समय भी काम किया जा सकता है. इसलिए, अगर आपका Drawable या View कोड कुछ ऐसा दिखता है:
Kotlin
fun setBitmap(bitmap: Bitmap) { mBitmap = bitmap invalidate() } override fun onDraw(canvas: Canvas) { canvas.drawBitmap(mBitmap, null, paint) }
Java
void setBitmap(Bitmap bitmap) { mBitmap = bitmap; invalidate(); } void onDraw(Canvas canvas) { canvas.drawBitmap(mBitmap, null, paint); }
इसे इससे बदला जा सकता है:
Kotlin
fun setBitmap(bitmap: Bitmap) { shaderPaint.shader = BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP) invalidate() } override fun onDraw(canvas: Canvas) { canvas.drawRoundRect(0f, 0f, width, height, 20f, 20f, shaderPaint) }
Java
void setBitmap(Bitmap bitmap) { shaderPaint.setShader( new BitmapShader(bitmap, TileMode.CLAMP, TileMode.CLAMP)); invalidate(); } void onDraw(Canvas canvas) { canvas.drawRoundRect(0, 0, width, height, 20, 20, shaderPaint); }
इसका इस्तेमाल बैकग्राउंड को सुरक्षित रखने के लिए भी किया जा सकता है. जैसे, बिटमैप के ऊपर ग्रेडिएंट बनाना और ColorMatrixColorFilter की मदद से इमेज को फ़िल्टर करना. ये दो अन्य सामान्य कार्रवाइयां हैं, जो बिटमैप में बदलाव करने के लिए की जाती हैं.
अगर आपको किसी और वजह से बिटमैप पर ड्रॉ करना है, तो हो सकता है कि आपको इसे कैश मेमोरी के तौर पर इस्तेमाल करना हो. ऐसे में, सीधे तौर पर Canvas को पास किए गए हार्डवेयर-ऐक्सलरेटेड View या Drawable पर ड्रॉ करने की कोशिश करें. अगर ज़रूरी हो, तो setLayerType() को LAYER_TYPE_HARDWARE के साथ कॉल करें, ताकि जटिल रेंडरिंग आउटपुट को कैश किया जा सके. इससे जीपीयू रेंडरिंग का फ़ायदा भी मिलता रहेगा.
रेंडरिंग परफ़ॉर्मेंस: RenderThread
कुछ Canvas कार्रवाइयों को रिकॉर्ड करने में कम खर्च आता है, लेकिन इससे RenderThread पर महंगा कंप्यूटेशन ट्रिगर होता है. Systrace आम तौर पर, इन समस्याओं के बारे में सूचनाएं भेजता है.
बड़े पाथ को ऐनिमेट करना
जब
Canvas.drawPath() को हार्डवेयर की मदद से तेज़ी से काम करने वाले Canvas
View पर कॉल किया जाता है, तो Android इन पाथ को पहले सीपीयू पर बनाता है और फिर उन्हें जीपीयू पर अपलोड करता है.
अगर आपके पास बड़े पाथ हैं, तो उन्हें फ़्रेम-टू-फ़्रेम में न बदलें, ताकि उन्हें कैश किया जा सके और आसानी से बनाया जा सके.
drawPoints(), drawLines(), और drawRect/Circle/Oval/RoundRect() ज़्यादा असरदार हैं. साथ ही, इनका इस्तेमाल करना बेहतर है. भले ही, आपने ज़्यादा ड्रॉ कॉल का इस्तेमाल किया हो.
Canvas.clipPath
clipPath(Path)
से क्लिप करने की प्रोसेस में ज़्यादा समय लगता है. इसलिए, आम तौर पर इसका इस्तेमाल नहीं करना चाहिए. जब
मुमकिन हो, तो नॉन-रेक्टैंगल में क्लिप करने के बजाय, शेप बनाने का विकल्प चुनें. यह बेहतर तरीके से काम करता है और एंटी-एलियासिंग की सुविधा के साथ काम करता है. उदाहरण के लिए, यहां दिए गए clipPath कॉल को अलग-अलग तरीके से दिखाया जा सकता है:
Kotlin
canvas.apply { save() clipPath(circlePath) drawBitmap(bitmap, 0f, 0f, paint) restore() }
Java
canvas.save(); canvas.clipPath(circlePath); canvas.drawBitmap(bitmap, 0f, 0f, paint); canvas.restore();
इसके बजाय, ऊपर दिए गए उदाहरण को इस तरह से दिखाएं:
Kotlin
paint.shader = BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP) // At draw time: canvas.drawPath(circlePath, mPaint)
Java
// One time init: paint.setShader(new BitmapShader(bitmap, TileMode.CLAMP, TileMode.CLAMP)); // At draw time: canvas.drawPath(circlePath, mPaint);
बिटमैप अपलोड
Android, बिटमैप को OpenGL टेक्सचर के तौर पर दिखाता है. जब किसी फ़्रेम में पहली बार बिटमैप दिखाया जाता है, तब उसे GPU पर अपलोड किया जाता है. इसे Systrace में इस तरह देखा जा सकता है: Texture upload(id) width x height. इसमें कुछ मिलीसेकंड लग सकते हैं. जैसा कि इमेज 2 में दिखाया गया है. हालांकि, इमेज को GPU के साथ दिखाना ज़रूरी है.
अगर इनमें ज़्यादा समय लग रहा है, तो सबसे पहले ट्रेस में चौड़ाई और ऊंचाई के नंबर देखें. पक्का करें कि स्क्रीन पर दिखने वाला बिटमैप, उस जगह से ज़्यादा बड़ा न हो जहां वह दिख रहा है. ऐसा होने पर, अपलोड करने में ज़्यादा समय लगता है और ज़्यादा मेमोरी खर्च होती है. आम तौर पर, बिटमैप लोड करने वाली लाइब्रेरी, सही साइज़ के बिटमैप का अनुरोध करने का तरीका उपलब्ध कराती हैं.
Android 7.0 में, बिटमैप लोडिंग कोड—आम तौर पर लाइब्रेरी से किया जाता है—prepareToDraw() को कॉल कर सकता है, ताकि ज़रूरत पड़ने से पहले ही अपलोड ट्रिगर हो जाए. इस तरह, RenderThread के इस्तेमाल में न होने पर ही अपलोड हो जाता है. डिकोड करने के बाद या किसी व्यू में बिट मैप को बाइंड करते समय ऐसा किया जा सकता है. हालांकि, इसके लिए आपको बिट मैप के बारे में जानकारी होनी चाहिए. आम तौर पर, बिटमैप लोड करने वाली लाइब्रेरी यह काम आपके लिए करती है. हालांकि, अगर आपको खुद इसे मैनेज करना है या यह पक्का करना है कि नए डिवाइसों पर अपलोड की सीमा न पहुंचे, तो अपने कोड में prepareToDraw() को कॉल करें.
prepareToDraw() की मदद से डिकोड करते समय इसे जल्दी ट्रिगर करें.थ्रेड शेड्यूल करने में देरी
थ्रेड शेड्यूलर, Android ऑपरेटिंग सिस्टम का वह हिस्सा होता है जो यह तय करता है कि सिस्टम में कौनसी थ्रेड चलनी चाहिए, कब चलनी चाहिए, और कितने समय तक चलनी चाहिए.
कभी-कभी, आपके ऐप्लिकेशन की यूज़र इंटरफ़ेस (यूआई) थ्रेड के ब्लॉक होने या न चलने की वजह से जंक होता है. Systrace अलग-अलग रंगों का इस्तेमाल करता है. जैसा कि तीसरे फ़िगर में दिखाया गया है, इससे यह पता चलता है कि कोई थ्रेड कब स्लीपिंग (ग्रे), रन करने के लिए तैयार (नीला: यह रन कर सकता है, लेकिन इसे अभी तक शेड्यूलर ने रन करने के लिए नहीं चुना है), चालू तौर पर रन कर रहा है (हरा) या अनइंटरप्टिबल स्लीप (लाल या नारंगी) मोड में है. यह थ्रेड शेड्यूल करने में होने वाली देरी की वजह से होने वाली जंक की समस्याओं को डीबग करने के लिए बहुत मददगार है.
अक्सर, बाइंडर कॉल की वजह से आपके ऐप्लिकेशन के एक्ज़ीक्यूशन में लंबे समय तक रुकावट आती है. बाइंडर कॉल, Android पर इंटर-प्रोसेस कम्यूनिकेशन (आईपीसी) का एक तरीका है. Android के बाद के वर्शन में, यूज़र इंटरफ़ेस (यूआई) थ्रेड के बंद होने की यह सबसे सामान्य वजहों में से एक है. आम तौर पर, इस समस्या को ठीक करने के लिए, ऐसे फ़ंक्शन को कॉल करने से बचें जो बाइंडर कॉल करते हैं. अगर ऐसा करना ज़रूरी है, तो वैल्यू को कैश मेमोरी में सेव करें या काम को बैकग्राउंड थ्रेड में ले जाएं. कोडबेस के बड़े होने पर, अगर सावधानी नहीं बरती जाती है, तो कुछ लो-लेवल के तरीके लागू करके, गलती से बाइंडर कॉल जोड़ा जा सकता है. हालांकि, ट्रेसिंग की मदद से इन समस्याओं का पता लगाया जा सकता है और उन्हें ठीक किया जा सकता है.
अगर आपके पास बाइंडर लेन-देन हैं, तो adb कमांड का इस्तेमाल करके, उनके कॉल स्टैक कैप्चर किए जा सकते हैं:
$ adb shell am trace-ipc start
… use the app - scroll/animate ...
$ adb shell am trace-ipc stop --dump-file /data/local/tmp/ipc-trace.txt
$ adb pull /data/local/tmp/ipc-trace.txt
कभी-कभी, getRefreshRate() जैसे सामान्य दिखने वाले कॉल, बाइंडर लेन-देन को ट्रिगर कर सकते हैं. साथ ही, बार-बार कॉल किए जाने पर बड़ी समस्याएं पैदा कर सकते हैं. समय-समय पर ट्रेसिंग करने से, इन समस्याओं का पता लगाने और उन्हें ठीक करने में मदद मिल सकती है.
trace-ipc का इस्तेमाल करें.अगर आपको बाइंडर गतिविधि नहीं दिख रही है, लेकिन इसके बावजूद यूज़र इंटरफ़ेस (यूआई) थ्रेड नहीं चल रही है, तो पक्का करें कि आप किसी लॉक या दूसरी थ्रेड से होने वाली किसी अन्य कार्रवाई का इंतज़ार न कर रहे हों. आम तौर पर, यूज़र इंटरफ़ेस (यूआई) थ्रेड को अन्य थ्रेड से मिले नतीजों का इंतज़ार नहीं करना पड़ता. अन्य थ्रेड को इस पर जानकारी पोस्ट करनी होगी.
ऑब्जेक्ट असाइन करना और गार्बेज कलेक्शन
ART को Android 5.0 में डिफ़ॉल्ट रनटाइम के तौर पर पेश किए जाने के बाद से, ऑब्जेक्ट ऐलोकेशन और गार्बेज कलेक्शन (GC) की समस्या काफ़ी कम हो गई है. हालांकि, अब भी इस अतिरिक्त काम से आपके थ्रेड पर असर पड़ सकता है. ऐसा कभी-कभी होने वाले इवेंट के जवाब में किया जा सकता है. जैसे, कोई उपयोगकर्ता किसी बटन पर टैप करता है. हालांकि, ध्यान रखें कि हर बार मेमोरी असाइन करने पर कुछ खर्च होता है. अगर यह एक ऐसे लूप में है जिसे बार-बार कॉल किया जाता है, तो जीसी पर लोड कम करने के लिए, मेमोरी को असाइन न करें.
Systrace से पता चलता है कि GC बार-बार चल रहा है या नहीं. साथ ही, Android Memory Profiler से पता चलता है कि मेमोरी कहां से बंट रही है. अगर हो सके, तो मेमोरी को बार-बार ऐलोकेट करने से बचें. खास तौर पर, छोटे लूप में ऐसा करने से बचें. इससे आपको कम समस्याएं होंगी.
Android के नए वर्शन पर, GC आम तौर पर HeapTaskDaemon नाम के बैकग्राउंड थ्रेड पर चलता है. ज़्यादा मेमोरी का इस्तेमाल करने का मतलब है कि GC पर ज़्यादा सीपीयू संसाधन खर्च किए जा सकते हैं. जैसा कि इमेज 5 में दिखाया गया है.
आपके लिए सुझाव
- ध्यान दें: JavaScript बंद होने पर लिंक का टेक्स्ट दिखता है
- अपने ऐप्लिकेशन की परफ़ॉर्मेंस की तुलना अन्य ऐप्लिकेशन से करना
- ऐप्लिकेशन की परफ़ॉर्मेंस को मेज़र करने के बारे में खास जानकारी
- ऐप्लिकेशन ऑप्टिमाइज़ करने के सबसे सही तरीके