रूबी में लीक ढूँढना
<पी> रिसाव का पता लगाना काफी सरल है। आपGC का उपयोग कर सकते हैं , ObjectSpace , और आपकी मेमोरी उपयोग में वृद्धि देखने के लिए आपके एपीएम टूल में आरएसएस ग्राफ़। लेकिन सिर्फ यह जानना कि आपके पास रिसाव है, इसे ठीक करने के लिए पर्याप्त नहीं है। आपको यह जानना होगा कि यह कहां से आ रहा है। कच्चे नंबर आपको यह नहीं बता सकते। <पी> सौभाग्य से, रूबी पारिस्थितिकी तंत्र के पास उन संख्याओं के संदर्भ को जोड़ने के लिए कुछ बेहतरीन उपकरण हैं। दो memory-profiler हैं और derailed_benchmarks . memory_profiler रूबी में
<पी> memory_profiler जेम एक बहुत ही सरल एपीआई और एक विस्तृत (यद्यपि थोड़ा भारी) आवंटित और बरकरार रखी गई मेमोरी रिपोर्ट प्रदान करता है - जिसमें आवंटित वस्तुओं की श्रेणियां, उनका आकार और जहां उन्हें आवंटित किया गया था, शामिल है। इसे हमारे लीक प्रोग्राम में जोड़ना सीधा है। <पी> ऐसी रिपोर्ट आउटपुट करना जो इसके समान दिखती है। <पी> यहां बहुत सारी जानकारी है, लेकिन आम तौर पर, allocated objects by location और retained objects by location लीक की तलाश करते समय अनुभाग सबसे उपयोगी हो सकते हैं। ये फ़ाइल स्थान हैं जो आवंटित वस्तुओं की संख्या के आधार पर वस्तुओं को आवंटित करते हैं। allocatedऑब्जेक्टreportके भीतर आवंटित (बनाए गए) सभी ऑब्जेक्ट हैं ब्लॉक.retainedऑब्जेक्ट वे ऑब्जेक्ट हैं जिन्हेंreportके अंत तक कचरा एकत्र नहीं किया गया है ब्लॉक. हमने ब्लॉक के अंत से पहले जीसी रन को मजबूर किया ताकि हम लीक हुई वस्तुओं को अधिक स्पष्ट रूप से देख सकें।
retained पर भरोसा करते समय सावधान रहें वस्तु गिनती. वे इस बात पर बहुत अधिक निर्भर करते हैं कि लीक होने वाले कोड का कौन सा भाग report के भीतर है ब्लॉक. <पी> उदाहरण के लिए, यदि हम an_array की घोषणा को आगे बढ़ाते हैं report में ब्लॉक करें, हम यह सोचकर मूर्ख बन सकते हैं कि कोड लीक नहीं हुआ है। <पी> परिणामी रिपोर्ट का शीर्ष कई रखी गई वस्तुओं की रिपोर्ट नहीं करेगा (सिर्फ रिपोर्ट ही)। derailed_benchmarks रूबी में
<पी> derailed_benchmarks जेम सभी प्रकार के प्रदर्शन कार्यों के लिए बहुत उपयोगी टूल का एक सूट है, जिसका उद्देश्य मुख्य रूप से रेल ऐप्स हैं। लीक खोजने के लिए, हम perf:mem_over_time को देखना चाहते हैं , perf:objects , औरperf:heap_diff . <पी> ये कार्य curl भेजकर कार्य करते हैं एक चालू ऐप के लिए अनुरोध, इसलिए हम उन्हें अपने छोटे से लीक प्रोग्राम में नहीं जोड़ सकते। इसके बजाय, हमें मेमोरी लीक करने वाले एंडपॉइंट के साथ एक स्मॉलरेल ऐप सेट अप करना होगा, फिर derailed_benchmarks इंस्टॉल करना होगा। उस ऐप पर. <पी> अब आपको bin/rails s के साथ ऐप को बूट करने में सक्षम होना चाहिए . आप curl कर पाएंगे एक समापन बिंदु जो प्रत्येक अनुरोध पर लीक हो जाता है। <पी> अब हम derailed_benchmarks का उपयोग कर सकते हैं हमारी लीक को क्रियान्वित होते देखने के लिए। perf:mem_over_time
<पी> यह हमें समय के साथ मेमोरी का उपयोग दिखाएगा (इसी तरह हमने watch के साथ अपनी लीक स्क्रिप्ट की थीममेमोरी वृद्धि को कैसे देखा था) और ps ). <पी> Derailed ऐप को प्रोडक्शन मोड में बूट करेगा, बार-बार एक एंडपॉइंट (/) को हिट करेगा डिफ़ॉल्ट रूप से), और मेमोरी उपयोग की रिपोर्ट करें। यदि यह कभी भी बढ़ना बंद नहीं करता है, तो हमारे पास एक रिसाव है! <पी> ध्यान दें :Derailed परीक्षण करने के लिए रेल्स ऐप को उत्पादन मोड में बूट करेगा। डिफ़ॉल्ट रूप से, यह require rails/all भी होगा प्रथम. चूँकि इस ऐप में हमारे पास कोई डेटाबेस नहीं है, इसलिए हमें इस व्यवहार को DERAILED_SKIP_ACTIVE_RECORD=true से ओवरराइड करना होगा . <पी> हम इस बेंचमार्क को विभिन्न समापन बिंदुओं के विरुद्ध चला सकते हैं यह देखने के लिए कि कौन सा (ifany) लीक हुआ है। perf:objects
<पी> perf:objects कार्य memory_profiler का उपयोग करता है हुड के नीचे ताकि उत्पादित रिपोर्ट परिचित दिखे। <पी> यह रिपोर्ट यह पता लगाने में मदद कर सकती है कि आपकी लीक हुई मेमोरी कहां आवंटित की जा रही है। हमारे उदाहरण में, रिपोर्ट का अंतिम खंड -Retained String Report — हमें सटीक रूप से बताता है कि हमारी समस्या क्या है। <पी> हमने LeaksController से "एबीसी" वाली 10,000 स्ट्रिंग्स लीक कर दी हैं ऑनलाइन 3. एक गैर-तुच्छ ऐप में, यह रिपोर्ट काफी बड़ी होगी और इसमें बरकरार स्ट्रिंग्स होंगी जिन्हें आप बनाए रखना चाहते हैं - क्वेरी कैश इत्यादि - लेकिन यह और अन्य 'स्थान के अनुसार' अनुभाग आपको अपने रिसाव को कम करने में मदद करेंगे। perf:heap_diff
<पी> perf:heap_diff यदि perf:objects की रिपोर्ट हो तो बेंचमार्क मदद कर सकता है यह देखना बहुत जटिल है कि आपका रिसाव कहाँ से हो रहा है। <पी> जैसा कि नाम से पता चलता है, perf:heap_diff तीन हीप डंप तैयार करता है और उनके बीच अंतर की गणना करता है। यह एक रिपोर्ट बनाता है जिसमें डंप और उन्हें आवंटित स्थान के बीच बनाए गए ऑब्जेक्ट के प्रकार शामिल होते हैं। <पी> आप 2021 में रूबी मेमोरी लीक को ट्रैक करना भी पढ़ सकते हैं बेहतर ढंग से समझने के लिए कि क्या हो रहा है। <पी> रिपोर्ट हमें ठीक-ठीक बताती है कि हमें अपने लीक बेबी ऐप के लिए कहां जाना है। अंतर के शीर्ष पर, हम LeaksController से आवंटित 999991 बरकरार स्ट्रिंग ऑब्जेक्ट देखते हैं लाइन 3 पर. रियल रूबी और रेल्स ऐप्स में लीक
<पी> उम्मीद है, हमने अब तक जिन उदाहरणों का उपयोग किया है, उन्हें कभी भी वास्तविक जीवन के ऐप्स में नहीं डाला गया है - मुझे आशा है कि कोई भी मेमोरी लीक करने का इरादा नहीं रखता है! <पी> गैर-तुच्छ ऐप्स में, मेमोरीलीक्स को ट्रैक करना बहुत कठिन हो सकता है। रखी हुई वस्तुएँ हमेशा ख़राब नहीं होतीं—कचरे से एकत्रित वस्तुओं वाला कैश अधिक उपयोगी नहीं होगा। <पी> हालाँकि, सभी लीक के बीच कुछ सामान्य बात है। कहीं न कहीं, एक रूट-लेवलऑब्जेक्ट (एक वर्ग/वैश्विक, आदि) किसी ऑब्जेक्ट का संदर्भ रखता है। <पी> एक सामान्य उदाहरण बिना सीमा वाला कैश या निष्कासन नीति है। परिभाषा के अनुसार, इससे मेमोरी लीक हो जाएगी क्योंकि कैश में डाली गई प्रत्येक वस्तु हमेशा के लिए रहेगी। समय के साथ, यह कैश किसी ऐप की अधिक से अधिक मेमोरी पर कब्ज़ा कर लेगा, जबकि इसका प्रतिशत वास्तव में उपयोग में कम और कम होता जाएगा। <पी> निम्नलिखित कोड पर विचार करें जो किसी गेम के लिए उच्च अंक प्राप्त करता है। यह उस चीज़ के समान है जो मैंने अतीत में देखी है। यह एक महँगा अनुरोध है, और कैश बदलने पर हम इसे आसानी से ख़त्म कर सकते हैं, इसलिए हम इसे कैश करना चाहते हैं। <पी>@scores हैश पूरी तरह से अनियंत्रित है. यह प्रत्येक उपयोगकर्ता के लिए प्रत्येक उच्च स्कोर को बनाए रखने के लिए विकसित होगा - यदि आपके पास बहुत अधिक है तो यह आदर्श नहीं है। <पी> रेल ऐप में, हम शायद Rails.cache का उपयोग करना चाहेंगे इसके बजाय एक समझदार समाप्ति के साथ (रेडिस में एक मेमोरी लीक अभी भी एक मेमोरी लीक है!) <पी> एक गैर-रेल ऐप में, हम सबसे पुराने या कम से कम हाल ही में उपयोग किए गए आइटम को हटाकर हैश आकार को सीमित करना चाहते हैं। LruRedux एक अच्छा कार्यान्वयन है. <पी> इस लीक का एक अधिक सूक्ष्म संस्करण एक सीमा वाला कैश है, लेकिन जिसकी कुंजियाँ मनमाने आकार की होती हैं। यदि चाबियाँ स्वयं बढ़ती हैं, तो कैश भी बढ़ेगा। आमतौर पर, आप इस पर प्रहार नहीं करेंगे। लेकिन, यदि आप ऑब्जेक्ट को JSON के रूप में क्रमबद्ध कर रहे हैं और उसे एक कुंजी के रूप में उपयोग कर रहे हैं, तो दोबारा जांच लें कि आप उन चीजों को क्रमबद्ध नहीं कर रहे हैं जो उपयोग के साथ-साथ बढ़ती हैं - जैसे उपयोगकर्ता के पढ़े गए संदेशों की सूची। परिपत्र संदर्भ
<पी> परिपत्र संदर्भ कर सकते हैं कूड़ा एकत्र किया जाए. रूबी में कचरा संग्रहण "मार्क एंड स्वीप" एल्गोरिदम का उपयोग करता है। वेरिएबलविड्थ आवंटन की शुरुआत करते हुए अपनी प्रस्तुति के दौरान, पीटर झू और मैट वेलेंटाइन-हाउस ने यह एल्गोरिदम कैसे काम करता है, इसकी उत्कृष्ट व्याख्या दी। <पी> मूलतः, दो चरण होते हैं:मार्किंग और स्वीपिंग।- <पी> चिन्हांकनमें चरण, कचरा संग्रहकर्ता रूट ऑब्जेक्ट्स (वर्ग, ग्लोबल इत्यादि) पर शुरू होता है, उन्हें चिह्नित करता है, और फिर उनके संदर्भ ऑब्जेक्ट्स को देखता है। <पी> इसके बाद यह सभी संदर्भित वस्तुओं को चिह्नित करता है। संदर्भित वस्तुएं जो पहले से ही चिह्नित हैं, उन्हें दोबारा नहीं देखा जाता है। यह तब तक जारी रहता है जब तक देखने के लिए कोई और वस्तु न रह जाए - यानी, सभी संदर्भित वस्तुओं को चिह्नित कर लिया गया हो।
- <पी> इसके बाद कचरा इकट्ठा करने वालासफाईकरने के लिए आगे बढ़ता है चरण. चिह्नित नहीं की गई किसी भी वस्तु को साफ़ कर दिया जाता है।
एप्लिकेशन प्रदर्शन मॉनिटरिंग:इवेंट टाइमलाइन और आवंटित ऑब्जेक्ट ग्राफ़
<पी> जैसा कि इस श्रृंखला के पहले भाग में बताया गया है, किसी भी उत्पादन-स्तर के ऐप को किसी न किसी रूप में एप्लिकेशन परफॉर्मेंस मॉनिटरिंग (एपीएम) का उपयोग करना चाहिए। <पी> कई विकल्प उपलब्ध हैं, जिनमें अपना खुद का रोल करना (केवल बड़ी टीमों के लिए अनुशंसित) शामिल है। एक प्रमुख विशेषता जो आपको एपीएम से प्राप्त करनी चाहिए वह है किसी कार्रवाई (या पृष्ठभूमि कार्य) द्वारा किए गए आवंटन की संख्या को देखने की क्षमता। अच्छे APMtools इसे तोड़ देंगे, जिससे यह जानकारी मिलेगी कि आवंटन कहाँ से आते हैं - नियंत्रक, दृश्य, आदि। <पी> इसे अक्सर 'इवेंट टाइमलाइन' जैसा कुछ कहा जाता है। बोनस अंक यदि आपका एपीएम आपको कस्टम कोड लिखने की अनुमति देता है जो समयरेखा को और तोड़ देता है। <पी> रेल नियंत्रक के लिए निम्नलिखित कोड पर विचार करें। <पी> जब किसी APM द्वारा रिपोर्ट किया जाता है, तो 'इवेंट टाइमलाइन' AppSignal के निम्नलिखित स्क्रीनशॉट की तरह कुछ दिखाई दे सकती है। <पी>
<पी> इसे यंत्रीकृत किया जा सकता है ताकि हम देख सकें कि कोड का कौन सा भाग समयरेखा में आवंटन करता है। वास्तविक ऐप्स में, यह संभवतः कोड 😅 से कम स्पष्ट होगा <पी> यहां एक बार फिर AppSignal से इंस्ट्रुमेंटेड इवेंट टाइमलाइन का एक उदाहरण दिया गया है: <पी>
<पी> यह जानना कि उपकरण कहाँ लगाना है अक्सर समझना मुश्किल हो सकता है। आपके एप्लिकेशन के कोड को वास्तव में समझने का कोई विकल्प नहीं है, लेकिन कुछ संकेत हैं जो 'गंध' के रूप में काम कर सकते हैं। <पी> यदि आपका एपीएम समय के साथ जीसी रन या आवंटन को सामने लाता है, तो आप यह देखने के लिए स्पाइक्स की तलाश कर सकते हैं कि क्या वे हिट होने वाले कुछ समापन बिंदुओं या कुछ चल रहे पृष्ठभूमि नौकरियों के साथ मेल खाते हैं। यहां ऐपसिग्नल के रूबी वीएम मैजिक डैशबोर्ड से एक और उदाहरण दिया गया है: <पी>
<पी> इस तरह से आवंटन को देखकर, हम स्मृति समस्याओं को देखते समय अपनी खोज को सीमित कर सकते हैं। इससे memory_profiler जैसे टूल का उपयोग करना बहुत आसान हो जाता है और derailed_benchmarks कुशलतापूर्वक. <पी> AppSignal के रूबी रत्न में नवीनतम परिवर्धन, जैसे आवंटन और GC आँकड़े ट्रैकिंग के बारे में पढ़ें। समापन
<पी> इस पोस्ट में, हमने कुछ ऐसे टूल के बारे में चर्चा की है जो मेमोरी लीक को ढूंढने और ठीक करने में मदद कर सकते हैं, जिनमेंmemory_profiler शामिल हैं। , derailed_benchmarks , perf:mem_over_time , perf:objects , perf:heap_diff , ऐपसिग्नल में इवेंट टाइमलाइन और आवंटित ऑब्जेक्ट ग्राफ़। <पी> मुझे आशा है कि आपको यह पोस्ट, भाग एक के साथ, आपके रूबी ऐप में मेमोरी लीक का निदान और समाधान करने में उपयोगी लगी होगी। <पी> हमारे द्वारा उपयोग किए गए टूल के बारे में और पढ़ें: memory_profilerderailed_benchmarks- लीकी रेल्स ऐप
GCमॉड्यूल दस्तावेज़ीकरणObjectSpaceमॉड्यूल दस्तावेज़ीकरण- कचरा संग्रहण गहन गोता
- परिवर्तनीय चौड़ाई आवंटन