हमें पता चला है कि नीचे दी गई पोस्ट नैट बर्कोपेक के 2017 के एक लेख पर आधारित है, जिसे 'अंडरस्टैंडिंग रूबी जीसी थ्रू जीसी.स्टेट' कहा जाता है। ऐसा प्रतीत होता है कि इस लेख के कुछ हिस्सों को साहित्यिक चोरी की गई थी, कुछ ऐसा जिससे हम तब तक अनजान थे जब तक कि मूल लेखक ने इसका उल्लेख नहीं किया। हम अपने सभी लेखों को प्रकाशित करने से पहले एक साहित्यिक चोरी उपकरण के माध्यम से चलाते हैं, लेकिन इसने इसे उठाया नहीं। इस अनजाने में हुई त्रुटि के लिए हम नैट और हमारे पाठकों से बहुत क्षमा चाहते हैं।
यह महत्वपूर्ण है कि आप समझें कि रूबी में कचरा संग्रहण कैसे काम करता है ताकि आपके ऐप के प्रदर्शन पर पूर्ण नियंत्रण बना रहे।
इस पोस्ट में, हम रूबी में कचरा संग्रहण को लागू करने और अनुकूलित करने के तरीके के बारे में जानेंगे।
चलो चलते हैं!
रूबी कचरा कलेक्टर मॉड्यूल
रूबी गारबेज कलेक्टर मॉड्यूल रूबी के मार्क और स्वीप कचरा संग्रहण तंत्र के लिए एक इंटरफ़ेस है।
हालांकि यह जरूरत पड़ने पर पृष्ठभूमि में स्वचालित रूप से चलता है, जीसी मॉड्यूल आपको आवश्यकता पड़ने पर जीसी को मैन्युअल रूप से कॉल करने देता है और यह जानकारी प्राप्त करता है कि कचरा संग्रह चक्र कैसे चल रहा है। मॉड्यूल कुछ पैरामीटर प्रदान करता है जिन्हें आप मॉडरेट प्रदर्शन में बदल सकते हैं।
इस मॉड्यूल के कुछ सबसे अधिक उपयोग किए जाने वाले तरीके हैं:
- प्रारंभ/कचरा_संग्रह करें :यह विधि कचरा संग्रहण चक्र को मैन्युअल रूप से आरंभ करती है।
- सक्षम/अक्षम करें :ये विधियाँ स्वचालित कचरा संग्रहण चक्र को सक्षम या अक्षम करती हैं। वे एक बूलियन मान लौटाते हैं जो दर्शाता है कि क्या ऑपरेशन सफल रहा।
- आंकड़े :यह विधि GC मॉड्यूल के प्रदर्शन का वर्णन करने वाली कुंजियों और मानों की एक सूची प्रदान करती है। हम अगले भाग में इन मीट्रिक्स पर विस्तार से नज़र डालेंगे।
रूबी कचरा कलेक्टर पैरामीटर्स को समझना
यह समझने के लिए कि रूबी का जीसी आंतरिक रूप से कैसे काम करता है, आइए जीसी मॉड्यूल के मेट्रिक्स को देखें। ताज़ा बूट किए गए irb पर निम्न कमांड चलाएँ:
puts GC.stat
आप देखेंगे कि आपकी स्क्रीन पर संख्याओं का एक गुच्छा कुछ इस तरह दिखाई दे रहा है:
{
:count=>12,
:heap_allocated_pages=>49,
:heap_sorted_length=>49,
:heap_allocatable_pages=>0,
:heap_available_slots=>19975,
:heap_live_slots=>19099,
:heap_free_slots=>876,
:heap_final_slots=>0,
:heap_marked_slots=>16659,
:heap_eden_pages=>49,
:heap_tomb_pages=>0,
:total_allocated_pages=>49,
:total_freed_pages=>0,
:total_allocated_objects=>66358,
:total_freed_objects=>47259,
:malloc_increase_bytes=>16216,
:malloc_increase_bytes_limit=>16777216,
:minor_gc_count=>10,
:major_gc_count=>2,
:remembered_wb_unprotected_objects=>191,
:remembered_wb_unprotected_objects_limit=>312,
:old_objects=>16024,
:old_objects_limit=>23556,
:oldmalloc_increase_bytes=>158824,
:oldmalloc_increase_bytes_limit=>16777216
}
यह इस बारे में सारी जानकारी रखता है कि रनटाइम में कचरा संग्रह कैसे हो रहा है। आइए इनमें से प्रत्येक संख्या की विस्तार से जाँच करें।
रूबी कचरा संग्रहकर्ता में गिना जाता है
हम इन चाबियों का वर्णन करके शुरू करेंगे:
{
:count=>12,
#…
:minor_gc_count=>10,
:major_gc_count=>2,
}
ये जीसी मायने रखता है, और वे बहुत सीधी जानकारी देते हैं। minor_gc_count
और major_gc_count
प्रत्येक प्रकार के कचरा संग्रहण के लिए चलाए जा रहे काउंट हैं।
रूबी में दो प्रकार के कचरा संग्रह होते हैं।
माइनर जीसी एक कचरा संग्रह प्रयास को संदर्भित करता है जो कचरा इकट्ठा करने की कोशिश करता है केवल उन वस्तुओं को इकट्ठा करता है जो नई हैं, यानी, वे तीन या उससे कम कचरा संग्रह चक्र से बच गए हैं।
दूसरी ओर, प्रमुख जीसी एक कचरा संग्रह प्रयास है जो सभी वस्तुओं को इकट्ठा करने का प्रयास करता है, यहां तक कि वे जो तीन से अधिक कचरा संग्रह चक्रों से बच गए हैं। count
minor_gc_count
. का योग है और major_gc_count
।
GC काउंट को ट्रैक करना कुछ कारणों से मददगार हो सकता है। आप यह पता लगा सकते हैं कि क्या कोई विशेष कार्य या प्रक्रिया हमेशा GC को ट्रिगर करती है और कितनी बार यह उन्हें ट्रिगर करती है। मल्टीथ्रेडेड एप्लिकेशन जैसे मामलों में यह 100% सटीक नहीं हो सकता है, लेकिन यह पता लगाने के लिए एक अच्छा प्रारंभिक बिंदु है कि आपकी मेमोरी कहाँ से ब्लीडिंग हो रही है।
हीप नंबर:स्लॉट और पेज
आगे, आइए इन चाबियों के बारे में बात करते हैं, जिन्हें हीप नंबर . के नाम से भी जाना जाता है :
{
# page numbers
:heap_allocated_pages=>49,
:heap_sorted_length=>49,
:heap_allocatable_pages=>0,
# slots
:heap_available_slots=>19975,
:heap_live_slots=>19099,
:heap_free_slots=>876,
:heap_final_slots=>0,
:heap_marked_slots=>16659,
# Eden and Tomb pages
:heap_eden_pages=>49,
:heap_tomb_pages=>0,
}
हम यहां जिस ढेर के बारे में बात कर रहे हैं वह एक सी डेटा संरचना है। इसमें वर्तमान में सभी रूबी वस्तुओं के संदर्भ शामिल हैं। ढेर पेज मेमोरी स्लॉट से बना है, और प्रत्येक स्लॉट में केवल एक लाइव रूबी ऑब्जेक्ट की जानकारी शामिल है:
heap_allocated_pages
वर्तमान में आवंटित ढेर पृष्ठों की संख्या है। ये पृष्ठ पूरी तरह से खाली, पूरी तरह से भरे या आंशिक रूप से भरे जा सकते हैं।heap_sorted_length
वास्तविक आकार है कि ढेर ने स्मृति में कब्जा कर लिया है औरheap_allocated_pages
से अलग है , क्योंकि लंबाई लंबाई . है ढेर के पन्नों को एक साथ रखा गया है, न कि उनकी गिनती . यदि आपने शुरू में 10 पृष्ठ आवंटित किए और फिर सेट के बीच से एक को मुक्त कर दिया, तो आपकाheap_allocated_pages
9 होगा, लेकिनheap_sorted_length
अभी भी 10 होगा.- आखिरकार,
heap_allocatable_pages
रूबी के पास वर्तमान में ढेरों की संख्या है जिसका उपयोग जरूरत पड़ने पर किया जा सकता है।
अब, स्लॉट पर आ रहे हैं:
heap_available_slots
हीप पृष्ठों में उपलब्ध स्लॉट की कुल संख्या है।heap_live_slots
स्मृति में जीवित वस्तुओं की संख्या है।heap_free_slots
आवंटित ढेर पृष्ठों में स्लॉट हैं जो खाली हैं।heap_final_slots
स्लॉट्स की गिनती है जिनके ऑब्जेक्ट में फाइनलाइज़र . हैं उनसे जुड़ा हुआ है। फ़ाइनलाइज़र वे प्रोसेस हैं जो किसी ऑब्जेक्ट के मुक्त होने पर चलते हैं, ठीक उसी तरह जैसे OOPS में डिस्ट्रक्टर्स होते हैं।heap_marked_slots
पुरानी वस्तुओं की गिनती है (यानी, वे वस्तुएं जो 3 जीसी चक्रों से अधिक समय से आसपास हैं) और राइट-बैरियर असुरक्षित वस्तुओं की संख्या है।
फिर हमारे पास tomb_pages
. है और eden_pages
।
tomb_pages
उन पृष्ठों की संख्या है जिनमें कोई सजीव वस्तु नहीं है। रूबी द्वारा इन पृष्ठों को अंततः ऑपरेटिंग सिस्टम पर वापस जारी कर दिया जाता है।
दूसरी ओर, eden_pages
उन पृष्ठों की गिनती है जिनमें कम से कम एक जीवित वस्तु है, इसलिए उन्हें ऑपरेटिंग सिस्टम पर वापस नहीं छोड़ा जा सकता है।
मीट्रिक heap_free_slots
. की निगरानी पर विचार करें यदि आप अपने एप्लिकेशन में मेमोरी ब्लोट समस्याओं का सामना करते हैं।
बड़ी संख्या में मुफ्त स्लॉट (250,000 से अधिक) आमतौर पर इंगित करते हैं कि आपके पास मुट्ठी भर नियंत्रक क्रियाएं हैं जो एक साथ कई वस्तुओं को आवंटित करती हैं और फिर उन्हें मुक्त करती हैं। यह आपकी चल रही रूबी प्रक्रिया के आकार को स्थायी रूप से बढ़ा सकता है।
संचयी संख्याएं
{
:total_allocated_pages=>49,
:total_freed_pages=>0,
:total_allocated_objects=>66358,
:total_freed_objects=>47259,
}
ये संख्याएँ प्रक्रिया के पूरे जीवन के लिए संचयी या योगात्मक प्रकृति की होती हैं। वे जीसी द्वारा कभी भी रीसेट नहीं किए जाते हैं और तकनीकी रूप से नीचे नहीं जा सकते हैं। ये चारों संख्याएँ स्वतः स्पष्ट हैं।
कचरा संग्रहण सीमाएं
इन नंबरों को समझने के लिए, आपको सबसे पहले यह समझना होगा कि GC कब ट्रिगर होता है:
{
:malloc_increase_bytes=>16216,
:malloc_increase_bytes_limit=>16777216,
:remembered_wb_unprotected_objects=>191,
:remembered_wb_unprotected_objects_limit=>312,
:old_objects=>16024,
:old_objects_limit=>23556,
:oldmalloc_increase_bytes=>158824,
:oldmalloc_increase_bytes_limit=>16777216
}
एक आम धारणा के विपरीत कि जीसी रन निश्चित अंतराल पर होता है, जब रूबी मेमोरी स्पेस से बाहर निकलने लगती है तो जीसी रन चालू हो जाते हैं। माइनर जीसी तब होता है जब रूबी free_slots
. से बाहर हो जाती है ।
अगर रूबी अभी भी free_slots
पर कम है मामूली जीसी रन के बाद - या ओल्डमॉलोक, मॉलोक, पुरानी ऑब्जेक्ट गिनती, या छायादार की दहलीज /राइट-बैरियर-असुरक्षित संख्या पार हो गई है - एक प्रमुख जीसी रन शुरू हो गया है। gc.stat का उपरोक्त भाग इन थ्रेसहोल्ड के मान दिखाता है।
malloc_increase_bytes
ढेर . के बाहर आवंटित स्मृति की मात्रा को संदर्भित करता है हमने अब तक बात की। जब किसी ऑब्जेक्ट का आकार मेमोरी स्लॉट के मानक आकार से अधिक हो जाता है - कहते हैं, 40 बाइट्स - रूबी malloc
बस उस वस्तु के लिए कहीं और जगह है। जब कुल अतिरिक्त आवंटित स्थान malloc_increase_bytes_limit
. से अधिक हो जाता है , एक प्रमुख GC चालू हो जाता है।
oldmalloc_increase_bytes
पुरानी वस्तुओं के लिए एक समान दहलीज है। old_objects
पुराने के रूप में चिह्नित ऑब्जेक्ट स्लॉट की संख्या है। जब संख्या old_objects_limit
. से अधिक हो जाती है , प्रमुख जीसी चालू हो गया है।
remembered_wb_unprotected_objects
उन वस्तुओं की कुल संख्या है जो राइट-बैरियर . द्वारा सुरक्षित नहीं हैं और याद किए गए सेट . का हिस्सा हैं ।
राइट-बैरियर रूबी रनटाइम और उसकी वस्तुओं के बीच का एक इंटरफ़ेस है, जो दुभाषिया को ऑब्जेक्ट बनाते ही उसके संदर्भों को ट्रैक करने की अनुमति देता है।
सी-एक्सटेंशन राइट-बैरियर का उपयोग किए बिना वस्तुओं के लिए नए संदर्भ बना सकते हैं, इस स्थिति में वस्तुओं को छायादार के रूप में चिह्नित किया जाता है या राइट-बैरियर असुरक्षित . याद किया गया सेट केवल पुराने . की एक सूची है नए . के कम से कम एक संदर्भ वाली वस्तुएं वस्तु।
रूबी कचरा संग्रहण प्रदर्शन अनुकूलित करें
अब जब आप समझ गए हैं कि रूबी जीसी आपके एप्लिकेशन की मेमोरी को कैसे प्रबंधित करती है, तो जीसी के व्यवहार को अनुकूलित करने के लिए उपलब्ध विकल्पों को देखने का समय आ गया है।
यहां पर्यावरण चर हैं जिनका उपयोग आप रूबी जीसी के प्रदर्शन को मॉडरेट करने के लिए कर सकते हैं और बदले में, अपने आवेदन के प्रदर्शन में सुधार कर सकते हैं:
RUBY_GC_HEAP_INIT_SLOTS
RUBY_GC_HEAP_FREE_SLOTS
RUBY_GC_HEAP_GROWTH_FACTOR
RUBY_GC_HEAP_GROWTH_MAX_SLOTS
RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR
and other variables
आइए यहां एक-एक करके महत्वपूर्ण मापदंडों के बारे में बात करते हैं:
RUBY_GC_HEAP_INIT_SLOTS
:रूबी ढेर पर स्लॉट की प्रारंभिक संख्या को परिभाषित करता है और डिफ़ॉल्ट रूप से 10000 पर सेट होता है। आप इस पैरामीटर को बदलना चाह सकते हैं यदि आप सुनिश्चित हैं कि आपका ऐप शुरू में अपने अधिकांश ऑब्जेक्ट आवंटित करेगा।RUBY_GC_HEAP_FREE_SLOTS
:जीसी चक्र के ठीक बाद उपलब्ध होने वाले मुफ्त स्लॉट की न्यूनतम संख्या को नियंत्रित करता है। इसका डिफ़ॉल्ट मान 4096 है। यह मान केवल पहली बार हीप वृद्धि के दौरान रनटाइम पर उपयोग किया जाता है।RUBY_GC_HEAP_GROWTH_FACTOR
:वह कारक जिसके द्वारा रूबी दुभाषिया के लिए उपलब्ध ढेर बढ़ते हैं। इसका डिफ़ॉल्ट मान 1.8 है। इसे बदलने का कोई मतलब नहीं है, क्योंकि रूबी पहले से ही ढेर के विकास में आक्रामक है। यदि आप इसे कम करने का प्रयास करते हैं तो इससे बहुत फर्क नहीं पड़ेगा क्योंकि आधुनिक दुभाषियों में ढेरों को मांग पर आवंटित किया जाता है।RUBY_GC_HEAP_GROWTH_MAX_SLOTS
:रूबी एक ही बार में ढेर स्थान में अधिकतम संख्या में स्लॉट जोड़ सकता है। डिफ़ॉल्ट मान 0 है, जिसका अर्थ है संख्या की कोई सीमा नहीं। यदि आपके ऐप को अपने जीवनकाल में लाखों ऑब्जेक्ट आवंटित करने की आवश्यकता है, तो हो सकता है कि आप इस पैरामीटर पर एक कैप लगाना चाहें। हालांकि, आपके ऐप के जीसी समय पर इसका बहुत कम प्रभाव पड़ेगा।RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR
जब स्मृति में पुरानी वस्तुओं की कुल संख्या =पिछले जीसी चक्र के बाद स्मृति में पुरानी वस्तुओं की संख्या x संख्या से अधिक होने पर दुभाषिया को एक प्रमुख जीसी चक्र करने के लिए मजबूर करता है। यदि आपको लगता है कि पुरानी पीढ़ी में प्रवेश करने के बाद आपकी कई वस्तुएं अनुपयोगी हो जाएंगी, तो आप इस संख्या को बढ़ाना चाह सकते हैं। हालांकि, इसकी शायद ही कभी आवश्यकता होती है।RUBY_GC_MALLOC_LIMIT
नई पीढ़ी के लिए मॉलोक कॉल की न्यूनतम सीमा है। इसका डिफ़ॉल्ट मान 16 एमबी है।RUBY_GC_MALLOC_LIMIT_MAX
एक ही मॉलोक कॉल के लिए अधिकतम सीमा है। इसका डिफ़ॉल्ट मान 32 एमबी है। यदि आपका एप्लिकेशन औसत मेमोरी से अधिक का उपयोग करता है, तो आप इन दो सीमाओं को बढ़ाना चाह सकते हैं। हालांकि, सावधान रहें कि इन्हें बहुत ज्यादा न बढ़ाएं। अन्यथा, वे उच्च शिखर स्मृति खपत को जन्म दे सकते हैं। इन सीमाओं को हमेशा बढ़ते हुए बढ़ाएँ — मान लीजिए, 4 या 8 एमबी।RUBY_GC_MALLOC_LIMIT_GROWTH_FACTOR
नई पीढ़ी के लिए मॉलोक सीमा का विकास कारक है। इसका डिफ़ॉल्ट मान 1.4 है। अगर आपका ऐप मेमोरी को एक बार में पूरा करने के बजाय टुकड़ों में आवंटित करता है, तो आपको इस संख्या को बढ़ाने पर विचार करना चाहिए।- इसी तरह,
RUBY_GC_OLDMALLOC_LIMIT
औरRUBY_GC_OLDMALLOC_LIMIT_MAX
पुरानी पीढ़ी के लिए न्यूनतम और अधिकतम मॉलोक सीमाएँ हैं। इन मापदंडों के डिफ़ॉल्ट मान 16 एमबी और 128 एमबी हैं। RUBY_GC_OLDMALLOC_LIMIT_GROWTH_FACTOR
इस सीमा का वृद्धि कारक है। इसका डिफ़ॉल्ट मान 1.2 है। अधिकतम प्रभाव के लिए आप इन्हें नई पीढ़ी की सीमाओं के साथ बदलने पर विचार कर सकते हैं।
रूबी में कचरा संग्रह को ठीक करना
हमने आपके एप्लिकेशन के समग्र प्रदर्शन को बेहतर बनाने में आपकी मदद करने के लिए GC मॉड्यूल को अनुकूलित करने के कुछ सामान्य और सरल तरीकों पर चर्चा की। हालाँकि, ये ट्वीक सभी मामलों में काम नहीं कर सकते हैं। क्या कस्टमाइज़ करना है, यह तय करने से पहले आपको अपने ऐप के मेमोरी उपयोग पैटर्न का पता लगाना होगा।
दूसरी तरफ, आप एक स्वचालित परीक्षण चलाने पर विचार कर सकते हैं जो आपके लिए इन मापदंडों के सर्वोत्तम मूल्यों को ढूंढता है। अपने पर्यावरण चर के लिए मूल्यों के सर्वोत्तम सेट का पता लगाते समय TuneMyGC जैसे उपकरण बहुत सीधे हैं।
यदि आपका आवेदन अजीब व्यवहार कर रहा है तो निश्चित रूप से जीसी पैरामीटर देखें। यहां एक छोटा सा बदलाव आपके ऐप की मेमोरी खपत को कम करने और मेमोरी ब्लोट को रोकने के लिए एक लंबा रास्ता तय कर सकता है।
मुझे उम्मीद है कि इस लेख ने आपको अपने रूबी कचरा संग्रह मॉड्यूल को अनुकूलित करते समय क्या देखना चाहिए, इसका एक अच्छा विचार दिया है। अधिक परिचय के लिए, कचरा संग्रहण भाग I और भाग II का परिचय देखें।
कोडिंग का मज़ा लें!