ईडन स्पेस
तो मेरा सवाल यह है कि क्या यह वास्तव में सच हो सकता है, और यदि ऐसा है तो जावा का ढेर इतनी तेजी से क्यों आवंटित किया गया है।
मैं इस बारे में थोड़ा अध्ययन कर रहा हूं कि जावा जीसी कैसे काम करता है क्योंकि यह मेरे लिए बहुत दिलचस्प है। मैं हमेशा सी और सी ++ में मेमोरी आवंटन रणनीतियों के अपने संग्रह का विस्तार करने की कोशिश कर रहा हूं (सी में कुछ इसी तरह को लागू करने की कोशिश में रुचि रखता हूं), और यह एक फट फैशन में बहुत सी वस्तुओं को आवंटित करने का एक बहुत तेज़ तरीका है व्यावहारिक दृष्टिकोण लेकिन मुख्य रूप से मल्टीथ्रेडिंग के कारण।
जिस तरह से जावा जीसी आवंटन कार्य करता है वह शुरू में "ईडन" अंतरिक्ष में वस्तुओं को आवंटित करने के लिए एक बेहद सस्ते आवंटन रणनीति का उपयोग करता है । मैं जो बता सकता हूं, वह एक अनुक्रमिक पूल आवंटनकर्ता का उपयोग कर रहा है।
एल्गोरिथ्म के मामले में यह पूरी तरह से तेज है और malloc
सी या डिफॉल्ट में सामान्य प्रयोजन की तुलना में अनिवार्य पृष्ठ दोष को कम करना , operator new
सी ++ में फेंकना है।
लेकिन अनुक्रमिक आवंटनकर्ताओं की एक कमजोर कमजोरी होती है: वे चर-आकार के विखंडू को आवंटित कर सकते हैं, लेकिन वे किसी भी व्यक्ति को विखंडित नहीं कर सकते। वे बस संरेखण के लिए पैडिंग के साथ एक सीधे अनुक्रमिक फैशन में आवंटित करते हैं, और केवल एक बार में आवंटित सभी मेमोरी को शुद्ध कर सकते हैं। वे डेटा संरचनाओं के निर्माण के लिए विशेष रूप से C और C ++ में उपयोगी होते हैं जिन्हें केवल खोज के पेड़ की तरह सम्मिलन और तत्वों को हटाने की आवश्यकता नहीं होती है, जिसे केवल एक प्रोग्राम शुरू होने पर केवल एक बार बनाया जाना चाहिए और फिर बार-बार खोजा जाता है या केवल नई कुंजियाँ जोड़ी जाती हैं ( कोई कुंजी नहीं निकाली गई)।
उनका उपयोग उन डेटा संरचनाओं के लिए भी किया जा सकता है जो तत्वों को निकालने की अनुमति देते हैं, लेकिन उन तत्वों को वास्तव में स्मृति से मुक्त नहीं किया जाएगा क्योंकि हम उन्हें व्यक्तिगत रूप से नहीं दे सकते हैं। अनुक्रमिक आवंटनकर्ता का उपयोग करने वाली ऐसी संरचना बस अधिक से अधिक मेमोरी का उपभोग करेगी, जब तक कि यह कुछ आस्थगित पास न हो जहां डेटा को एक अलग अनुक्रमिक आवंटनकर्ता का उपयोग करके एक ताजा, कॉम्पैक्ट कॉपी में कॉपी किया गया था (और कभी-कभी एक बहुत प्रभावी तकनीक होती है अगर एक निश्चित आवंटन जीता जाता है किसी कारण के लिए नहीं - बस सीधे क्रमिक रूप से डेटा संरचना की एक नई प्रति आवंटित करें और पुराने की सभी मेमोरी को डंप करें)।
संग्रह
जैसा कि ऊपर डेटा संरचना / अनुक्रमिक पूल उदाहरण में, यह एक बड़ी समस्या होगी यदि जावा जीसी ने केवल इस तरह से आवंटित किया, भले ही यह कई व्यक्तिगत विखंडू के फटने के आवंटन के लिए सुपर फास्ट है। यह सॉफ्टवेयर बंद होने तक कुछ भी मुफ्त नहीं कर सकेगा, जिस बिंदु पर यह सभी मेमोरी पूल को एक साथ मुफ्त (शुद्ध) कर सकता है।
इसलिए, इसके बजाय, एक एकल जीसी चक्र के बाद, "ईडन" अंतरिक्ष (क्रमिक रूप से आवंटित) में मौजूदा वस्तुओं के माध्यम से एक पास बनाया जाता है, और जिन्हें अभी भी संदर्भित किया जाता है, वे एक और सामान्य-उद्देश्य आवंटनकर्ता का उपयोग करके आवंटित किया जाता है जो अलग-अलग विखंडों से मुक्त करने में सक्षम होता है। अब जिन संदर्भों को संदर्भित नहीं किया जाता है, उन्हें केवल शुद्ध करने की प्रक्रिया में निपटाया जाएगा। तो मूल रूप से यह "ईडन अंतरिक्ष से वस्तुओं को कॉपी करें यदि वे अभी भी संदर्भित हैं, और फिर शुद्ध करें"।
यह आम तौर पर काफी महंगा होगा, इसलिए मूल रूप से सभी मेमोरी को आवंटित करने वाले धागे को रोकने के लिए एक अलग पृष्ठभूमि थ्रेड में किया जाता है।
एक बार मेमोरी को ईडन स्पेस से बाहर कॉपी किया जाता है और इस अधिक महंगी योजना का उपयोग करके आवंटित किया जाता है जो प्रारंभिक जीसी चक्र के बाद व्यक्तिगत चोंच को मुक्त कर सकता है, ऑब्जेक्ट एक अधिक निरंतर मेमोरी क्षेत्र में चले जाते हैं। यदि वे संदर्भित हो जाते हैं, तो उन व्यक्तिगत विखंडनों को बाद के GC चक्रों में मुक्त कर दिया जाता है।
गति
अतः, गंभीर रूप से कहें, तो यह कारण है कि जावा जीसी सीधे ढेर आवंटन में C या C ++ को बेहतर ढंग से बेहतर बना सकता है क्योंकि यह थ्रेड में सबसे सस्ती, पूरी तरह से डीजनरलाइज्ड आवंटन रणनीति का उपयोग कर रहा है जो मेमोरी आवंटित करने का अनुरोध करता है। तब यह अधिक महंगे काम को बचाता है जो हमें सामान्य रूप से एक malloc
और थ्रेड के लिए सीधे-अप जैसे अधिक सामान्य आवंटनक का उपयोग करते समय करना होगा ।
इसलिए वैचारिक रूप से जीसी को वास्तव में और अधिक काम करना है, लेकिन यह धागे के पार वितरित कर रहा है ताकि पूरी लागत का भुगतान एक ही धागे से न हो। यह थ्रेड को मेमोरी को सुपर सस्ते करने के लिए आवंटित करने की अनुमति देता है, और फिर चीजों को ठीक से करने के लिए आवश्यक वास्तविक व्यय को स्थगित कर देता है ताकि व्यक्तिगत वस्तुओं को वास्तव में दूसरे धागे से मुक्त किया जा सके। C या C ++ में जब हम malloc
या कॉल करते हैं operator new
, तो हमें एक ही थ्रेड के भीतर पूरी लागत का भुगतान करना होता है।
यह मुख्य अंतर यह है, और क्यों जावा बहुत अच्छी तरह से मात सकता है सी या सी ++ के लिए सिर्फ भोली कॉल का उपयोग malloc
या operator new
व्यक्तिगत रूप से नन्हा मात्रा का एक समूह आवंटित करने के लिए। बेशक जीसी चक्र में किक करने पर आमतौर पर कुछ परमाणु संचालन और कुछ संभावित लॉकिंग होने जा रहे हैं, लेकिन यह शायद थोड़ा बहुत अनुकूलित है।
मूल रूप से सरल व्याख्या एक धागे में भारी लागत का भुगतान करने के लिए उकसाती है ( malloc
) बनाम एक एकल धागे में सस्ती लागत का भुगतान करना और फिर दूसरे में भारी लागत का भुगतान करना जो समानांतर ( GC
) में चल सकता है । एक नकारात्मक पहलू के रूप में, इस तरह से करने का अर्थ है कि आपको ऑब्जेक्ट के संदर्भ से ऑब्जेक्ट के लिए दो अप्रत्यक्ष की आवश्यकता होती है, क्योंकि आवंटनकर्ता को मौजूदा ऑब्जेक्ट संदर्भों को अमान्य किए बिना स्मृति को कॉपी / स्थानांतरित करने की अनुमति देने की आवश्यकता होती है, और एक बार मेमोरी खो जाने पर आप स्थानिक स्थान भी खो सकते हैं। "ईडन" अंतरिक्ष से बाहर चले गए।
अंतिम लेकिन कम से कम, तुलना थोड़ा अनुचित है क्योंकि C ++ कोड सामान्य रूप से ढेर पर व्यक्तिगत रूप से वस्तुओं का एक नाव लोड आवंटित नहीं करता है। Decent C ++ कोड सन्निहित ब्लॉकों में या ढेर पर कई तत्वों के लिए मेमोरी आवंटित करने के लिए जाता है। अगर यह मुफ्त की दुकान पर एक समय में एक छोटी वस्तुओं का एक बोट लोड आवंटित करता है, तो कोड चमकदार है।