सी हीप की तुलना में जावा हीप आवंटन आवंटन


13

मैं पहले से ही एसओ पर यह सवाल पोस्ट कर चुका हूं और यह ठीक रहा। यह दुर्भाग्य से बंद कर दिया गया था (फिर से खोलने के लिए केवल एक वोट की जरूरत है), लेकिन किसी ने सुझाव दिया कि मैं इसे यहां पोस्ट कर दूं क्योंकि यह एक बेहतर फिट है इसलिए निम्नलिखित का शाब्दिक रूप से प्रश्न का एक कॉपी पेस्ट है


मैं इस उत्तर पर टिप्पणियों को पढ़ रहा था और मैंने यह उद्धरण देखा।

ऑब्जेक्ट तात्कालिकता और ऑब्जेक्ट-ओरिएंटेड सुविधाओं का उपयोग करने के लिए तेज़ी से धधक रहे हैं (कई मामलों में C ++ की तुलना में तेज़) क्योंकि वे शुरुआत से डिज़ाइन किए गए हैं। और संग्रह तेज हैं। मानक जावा इस क्षेत्र में मानक C / C ++ को धड़कता है, यहां तक ​​कि सबसे अनुकूलित C कोड के लिए भी।

एक उपयोगकर्ता (वास्तव में उच्च प्रतिनिधि के साथ मैं जोड़ सकता हूँ) साहसपूर्वक इस दावे का बचाव किया, यह बताते हुए

  1. जावा में ढेर का आवंटन C ++ की तुलना में बेहतर है

  2. और जावा में संग्रह का बचाव करते हुए इस कथन को जोड़ा

    और जावा संग्रह सी + + संग्रह की तुलना में बड़े पैमाने पर विभिन्न मेमोरी सबसिस्टम के कारण तेजी से होता है।

तो मेरा सवाल यह है कि क्या यह वास्तव में सच हो सकता है, और यदि ऐसा है तो जावा का ढेर इतनी तेजी से क्यों आवंटित किया गया है।


आपको एसओ उपयोगी / प्रासंगिक पर एक समान प्रश्न पर मेरा उत्तर मिल सकता है ।
डेनियल प्राइडेन

1
यह तुच्छ है: जावा (या किसी भी अन्य प्रबंधित, प्रतिबंधित वातावरण) के साथ आप ऑब्जेक्ट्स को स्थानांतरित कर सकते हैं और उनके लिए पॉइंटर्स अपडेट कर सकते हैं - यानी, गतिशील रूप से बेहतर कैश स्थानीयता के लिए अनुकूलित करें। C ++ और इसके सूचक अंकगणित के साथ अनियंत्रित बिटकास्ट के साथ सभी वस्तुओं को हमेशा के लिए उनके स्थान पर पिन कर दिया जाता है।
SK- तर्क

3
मैंने कभी नहीं सोचा था कि मैं किसी को जावा मेमोरी मैनेजमेंट कहते हुए सुनूंगा क्योंकि यह हर समय मेमोरी को कॉपी करता है। आह।
gbjbaanb

1
@ जीबीजैनब, क्या आपने कभी मेमोरी पदानुक्रम के बारे में सुना है? कैश मिस पेनल्टी? क्या आपको पता है कि एक सामान्य उद्देश्य आवंटन महंगा है, जबकि एक पहली पीढ़ी का आवंटन केवल एक अतिरिक्त संचालन है?
SK-तर्क

1
हालांकि यह कुछ मामलों में कुछ हद तक सही हो सकता है, यह इस बिंदु को याद करता है कि जावा में आप ढेर पर सब कुछ आवंटित करते हैं और सी ++ में आप ढेर पर ऑब्जेक्ट का एक बड़ा सौदा आवंटित करते हैं जो अभी भी बहुत तेज हो सकता है।
जॉन

जवाबों:


23

यह एक दिलचस्प सवाल है, और जवाब जटिल है।

कुल मिलाकर, मुझे लगता है कि यह कहना उचित है कि जेवीएम कचरा संग्राहक बहुत अच्छी तरह से डिज़ाइन किया गया है और बेहद कुशल है। यह शायद सबसे अच्छा सामान्य उद्देश्य स्मृति प्रबंधन प्रणाली है।

सी ++ जेवीएम जीसी को विशिष्ट मेमोरी एलोकेटर्स के साथ हरा सकता है जो विशिष्ट उद्देश्यों के लिए डिज़ाइन किए गए हैं। उदाहरण हो सकते हैं:

  • प्रति-फ्रेम मेमोरी एलोकेटर, जो आवधिक अंतराल पर पूरे मेमोरी क्षेत्र को पोंछते हैं। ये अक्सर C ++ गेम्स में उपयोग किए जाते हैं, उदाहरण के लिए, जहां एक अस्थायी मेमोरी क्षेत्र प्रति फ्रेम एक बार उपयोग किया जाता है और तुरंत खारिज कर दिया जाता है।
  • कस्टम आबंटक निश्चित आकार की वस्तुओं के एक पूल का प्रबंधन करते हैं
  • स्टैक आधारित आवंटन (हालांकि ध्यान दें कि जेवीएम विभिन्न परिस्थितियों में भी करता है, उदाहरण के लिए बच विश्लेषण के माध्यम से )

निश्चित रूप से, विशिष्ट मेमोरी एलोकेटर परिभाषा द्वारा सीमित हैं। उनके पास आमतौर पर ऑब्जेक्ट जीवनचक्र पर प्रतिबंध और / या उस प्रकार के ऑब्जेक्ट पर प्रतिबंध होते हैं जिन्हें प्रबंधित किया जा सकता है। कचरा संग्रह अधिक लचीला है।

कचरा संग्रह भी आपको प्रदर्शन के दृष्टिकोण से कुछ महत्वपूर्ण लाभ प्रदान करता है:

  • ऑब्जेक्ट इंस्टेंटेशन वास्तव में बहुत तेज़ है। जिस तरह से नई वस्तुओं को क्रमिक रूप से मेमोरी में आवंटित किया जाता है, उसके लिए अक्सर एक से अधिक पॉइंटर जोड़ की आवश्यकता होती है, जो निश्चित रूप से विशिष्ट सी ++ हीप एलोकेशन एल्गोरिदम की तुलना में तेज है।
  • आप जीवन चक्र प्रबंधन लागतों की आवश्यकता से बचते हैं - उदाहरण के संदर्भ की गिनती (कभी-कभी जीसी के विकल्प के रूप में उपयोग की जाती है) एक प्रदर्शन के दृष्टिकोण से बहुत खराब है क्योंकि संदर्भ की गिनती में लगातार वृद्धि और गिरावट के कारण बहुत अधिक प्रदर्शन ओवरहेड हो जाता है (आमतौर पर जीसी से अधिक) ।
  • यदि आप अपरिवर्तनीय वस्तुओं का उपयोग करते हैं, तो आप मेमोरी को बचाने और कैश दक्षता में सुधार करने के लिए संरचनात्मक साझाकरण का लाभ उठा सकते हैं । यह JVM जैसे स्काला और क्लोजर पर कार्यात्मक भाषाओं द्वारा भारी उपयोग किया जाता है। जीसी के बिना ऐसा करना बहुत मुश्किल है, क्योंकि साझा वस्तुओं के जीवनकाल को प्रबंधित करना बेहद कठिन है। यदि आप मानते हैं (जैसा कि मैं करता हूँ) कि अपरिपक्वता और संरचनात्मक साझेदारी बड़े समवर्ती अनुप्रयोगों के निर्माण के लिए महत्वपूर्ण है, तो यह यकीनन जीसी का सबसे बड़ा प्रदर्शन लाभ है।
  • यदि सभी प्रकार की वस्तु और उनके संबंधित जीवनचक्र को एक ही कचरा संग्रहण प्रणाली द्वारा प्रबंधित किया जाता है तो आप नकल से बच सकते हैं। C ++ के साथ विरोधाभास, जहां आपको अक्सर डेटा की पूर्ण प्रतियां लेनी पड़ती हैं क्योंकि गंतव्य को एक अलग मेमोरी प्रबंधन दृष्टिकोण की आवश्यकता होती है या एक अलग ऑब्जेक्ट जीवन चक्र होता है।

जावा जीसी का एक प्रमुख नकारात्मक पहलू है: क्योंकि कचरा इकट्ठा करने का काम समय-समय पर अंतराल पर किया जाता है और काम के सिलसिले में किया जाता है, इससे कचरा इकट्ठा करने में कभी-कभी जीसी रुक जाता है, जो विलंबता को प्रभावित कर सकता है। यह आमतौर पर विशिष्ट अनुप्रयोगों के लिए एक समस्या नहीं है, लेकिन उन स्थितियों में जावा पर शासन कर सकता है जहां कठिन समय की आवश्यकता होती है (जैसे रोबोट नियंत्रण)। नरम रीयलटाइम (जैसे गेम, मल्टीमीडिया) आमतौर पर ठीक है।


सी ++ क्षेत्र में विशेष पुस्तकालय हैं जो उस समस्या का समाधान करते हैं। इसके लिए शायद सबसे प्रसिद्ध उदाहरण स्मार्टहाइप है।
टोबियास लैंगनर

5
नरम-वास्तविक समय का मतलब यह नहीं है कि आप आमतौर पर बंद करने के लिए ठीक हैं । इसका मतलब सिर्फ इतना है कि आप वास्तविक बुरी स्थिति में रोक सकते हैं / फिर से प्रयास कर सकते हैं - आमतौर पर अप्रत्याशित - हॉल्ट / क्रैश / विफलता के बजाय। कोई भी आमतौर पर संगीत खिलाड़ी को रोकने का उपयोग नहीं करना चाहेगा। जीसी ठहराव की समस्या यह आमतौर पर और अप्रत्याशित रूप से होती है । उस तरीके से, सॉफ्ट-रियलटाइम एप्लिकेशन के लिए भी GC पॉज़ स्वीकार्य नहीं है। जीसी ठहराव तभी स्वीकार्य है जब उपयोगकर्ता आवेदन की गुणवत्ता की परवाह नहीं करते हैं। और आजकल, लोग अब उतने भोले नहीं हैं।
Eonil

1
कृपया अपने दावों का समर्थन करने के लिए कुछ प्रदर्शन माप पोस्ट करें, अन्यथा हम सेब और संतरे की तुलना कर रहे हैं।
JBRWilkinson

1
@ डेमेट्री लेकिन वास्तव में, कि अगर मामला बहुत ज्यादा होता है (और फिर से, यहां तक ​​कि अप्रत्याशित रूप से भी!) जब तक आप कुछ अव्यवहारिक बाधाओं को संतुष्ट नहीं कर सकते। दूसरे शब्दों में, C ++ किसी भी रीयलटाइम स्थिति के लिए बहुत आसान है।
Eonil

1
पूर्णता के लिए: GC प्रदर्शन-वार का एक और नकारात्मक पहलू है: जैसा कि अधिकांश-मौजूदा-जीसी में मुक्त मेमोरी एक और धागे में होती है, जो एक अलग कोर पर चलने की संभावना है, इसका मतलब है कि जीसीएस सिंकिंग के लिए गंभीर कैश अमान्य लागत खर्च कर रहे हैं विभिन्न कोर के बीच एल 1 / एल 2 कैश; इसके अलावा, उन सर्वरों पर, जो मुख्य रूप से NUMA हैं, L3 कैश को भी सिंक्रनाइज़ किया जाना है (और हाइपरट्रांसपोर्ट / QPI, ouch (!)) पर।
नहीं-बग्स हरे

3

यह कोई वैज्ञानिक दावा नहीं है। मैं बस इस मुद्दे पर विचार के लिए कुछ भोजन दे रहा हूं।

एक दृश्य सादृश्य यह है: आपको एक अपार्टमेंट (एक आवासीय इकाई) दिया जाता है जो कि कालीन है। कालीन गंदा है। अपार्टमेंट के फर्श को साफ करने के लिए सबसे तेज़ तरीका (घंटों के संदर्भ में) क्या है?

उत्तर: बस पुराने कालीन को रोल करें; फेंक देना; और एक नया कालीन बाहर रोल।

हम यहां क्या उपेक्षा कर रहे हैं?

  • मौजूदा व्यक्तिगत सामान बाहर ले जाने और फिर अंदर जाने की लागत।
    • यह कचरा संग्रहण की "स्टॉप-द-वर्ल्ड" लागत के रूप में जाना जाता है।
  • नए कालीन की लागत।
    • जो, संयोग से रैम के लिए, यह मुफ़्त है।

कचरा संग्रहण एक बहुत बड़ा विषय है और प्रोग्रामर.ईएस और स्टैकऑवरफ्लो दोनों में बहुत सारे प्रश्न हैं।

एक साइड इश्यू पर, C / C ++ आवंटन प्रबंधक जिसे TCMalloc के रूप में जाना जाता है, ऑब्जेक्ट रेफरेंस काउंटिंग के साथ सैद्धांतिक रूप से किसी भी GC सिस्टम के सर्वश्रेष्ठ प्रदर्शन के दावों को पूरा करने में सक्षम है।


वास्तव में c ++ 11 में भी एक कचरा संग्रह ABI है , यह कुछ ऐसे ही उत्तरों से
मिलता

यह मौजूदा C / C ++ प्रोग्राम (कोड बेस, जैसे Linux kernels और archaic_but_still_economically_important पुस्तकालयों जैसे libtiff) को तोड़ने का डर है जो C ++ में भाषा नवाचार की प्रगति में बाधा है।
6

समझ में आता है, मुझे लगता है कि सी + + 17 से यह अधिक पूर्ण होगा, लेकिन सच्चाई यह है कि एक बार जब आप वास्तव में सी ++ में प्रोग्राम करना सीखते हैं, तो आप इसे अब और नहीं चाहते हैं, शायद वे दो मुहावरों को संयोजित करने का एक तरीका ढूंढ सकते हैं। अच्छी तरह से
aaronman

क्या आपको एहसास है कि कचरा लेने वाले ऐसे हैं जो दुनिया को रोकते नहीं हैं? क्या आपने कॉम्पैक्टीकरण (जीसी तरफ) और ढेर विखंडन (जेनेरिक सी ++ आवंटन के लिए) के प्रदर्शन निहितार्थ पर विचार किया है?
SK- तर्क

2
मुझे लगता है कि इस सादृश्य में मुख्य दोष यह है कि जीसी वास्तव में गंदे बिट्स को खोजने के लिए क्या करता है, उन्हें काट दिया और फिर एक नया कालीन बनाने के लिए शेष बिट्स को एक साथ वापस देखा।
svick

3

मुख्य कारण यह है कि, जब आप जावा से मेमोरी की एक नई गांठ के लिए पूछते हैं, तो यह सीधे ढेर के अंत में जाता है और आपको एक ब्लॉक देता है। इस तरह, मेमोरी आवंटन स्टैक पर आवंटित करने के रूप में तेजी से होता है (जो कि आप इसे C / C ++ में अधिकतर समय करते हैं, लेकिन इसके अलावा ..)

तो आवंटन कुछ भी के रूप में तेजी से कर रहे हैं, लेकिन ... यह स्मृति को मुक्त करने की लागत की गणना नहीं करता है। सिर्फ इसलिए कि आप कुछ भी मुक्त नहीं करते हैं जब तक कि बाद में इसका मतलब यह नहीं है कि इसकी लागत बहुत अधिक नहीं है, और जीसी प्रणाली के मामले में, लागत 'सामान्य' ढेर आवंटन की तुलना में काफी अधिक है - न केवल जीसी को सभी वस्तुओं के माध्यम से यह देखने के लिए दौड़ना पड़ता है कि वे जीवित हैं या नहीं, इसे भी उन्हें मुक्त करना होगा, और (बड़ी लागत) ढेर को कॉम्पैक्ट करने के लिए मेमोरी को कॉपी करें - ताकि आपके पास अंत में तेजी से आवंटन हो सके तंत्र (या आप स्मृति से बाहर चलेंगे, उदाहरण के लिए C / C ++ प्रत्येक आवंटन पर ढेर चलेंगे, जो रिक्त स्थान के अगले ब्लॉक की तलाश कर रहे हैं जो ऑब्जेक्ट को फिट कर सकते हैं)।

यह एक कारण है कि जावा / .NET बेंचमार्क इस तरह के अच्छे प्रदर्शन को दिखाते हैं, फिर भी वास्तविक दुनिया के अनुप्रयोग इस तरह के खराब प्रदर्शन को दिखाते हैं। मैं सिर्फ अपने फोन पर क्षुधा को देखने के लिए है - वास्तव में तेजी से, उत्तरदायी लोगों को कर रहे हैं सभी NDK का उपयोग कर लिखा है, इतना तो भी मैं आश्चर्यचकित था।

आजकल संग्रह तेजी से हो सकता है अगर सभी वस्तुओं को स्थानीय रूप से आवंटित किया जाता है, जैसे कि एक एकल सन्निहित ब्लॉक में। अब, जावा में, आपको बस सन्निहित ब्लॉक नहीं मिलते हैं क्योंकि ऑब्जेक्ट्स को ढेर के मुक्त छोर से एक समय में आवंटित किया जाता है। आप उनके साथ ख़ुशी से सन्तुष्ट हो सकते हैं, लेकिन केवल भाग्य से (यानी जीसी संघनन दिनचर्या के चक्कर में और यह वस्तुओं को कैसे कॉपी करता है)। दूसरी ओर सी / सी ++ स्पष्ट रूप से सन्निहित आवंटन (स्टैक के माध्यम से, स्पष्ट रूप से) का समर्थन करता है। आमतौर पर C / C ++ में ढेर वस्तुओं जावा के BTW से अलग नहीं है।

अब C / C ++ के साथ आप डिफ़ॉल्ट एलोकेटर से बेहतर प्राप्त कर सकते हैं जो मेमोरी को बचाने और कुशलता से उपयोग करने के लिए डिज़ाइन किए गए थे। आप आवंटनकर्ता को फिक्स्ड-ब्लॉक पूल के सेट से बदल सकते हैं, इसलिए आप हमेशा एक ब्लॉक पा सकते हैं जो आपके द्वारा आवंटित वस्तु के लिए बिल्कुल सही आकार है। ढेर को चलना बस एक बिटमैप देखने का विषय बन जाता है यह देखने के लिए कि एक नि: शुल्क ब्लॉक कहां है, और डी-आवंटन बस उस बिटमैप में एक बिट को फिर से सेट कर रहा है। लागत यह है कि आप निश्चित-आकार वाले ब्लॉकों में आवंटित के रूप में अधिक मेमोरी का उपयोग करते हैं, इसलिए आपके पास 4 बाइट ब्लॉक का ढेर है, 16 बाइट ब्लॉक के लिए एक और है, आदि।


2
ऐसा लगता है कि आप जीसी को बिल्कुल भी नहीं समझते हैं। सबसे विशिष्ट परिदृश्य पर विचार करें - सैकड़ों छोटी वस्तुओं को लगातार आवंटित किया जाता है, लेकिन उनमें से केवल एक दर्जन एक सेकंड से अधिक समय तक जीवित रहेंगे। इस तरह, मेमोरी को मुक्त करने में कोई लागत नहीं है - इस दर्जन को युवा पीढ़ी (और एक अतिरिक्त लाभ के रूप में संकुचित) से कॉपी किया जाता है, और शेष को बिना किसी लागत के छोड़ दिया जाता है। और, दयनीय जीसीविक जीसी का आधुनिक, अत्याधुनिक जीसीएस से कोई लेना-देना नहीं है जिसे आप उचित जेवीएम कार्यान्वयन में पाएंगे।
SK-तर्क

1
यदि उन मुक्त वस्तुओं में से एक ढेर के बीच में है, तो शेष ढेर को अंतरिक्ष में पुनः प्राप्त करने के लिए जमा किया जाएगा। या आप कह रहे हैं कि जीसी कंपटीशन तब तक नहीं होता है जब तक इसका सबसे अच्छा मामला नहीं हो सकता है? मुझे पता है कि जेनरिक जीसी यहां बहुत अच्छा करते हैं, जब तक कि आप बाद की पीढ़ियों के बीच में एक वस्तु को जारी नहीं करते हैं, इस मामले में प्रभाव अपेक्षाकृत बड़ा हो सकता है। एक Microsoftie द्वारा लिखा गया कुछ था जो उनके GC पर काम करता था, जो मैंने पढ़ा कि जेनरिक GC बनाते समय GC ट्रेडऑफ का वर्णन किया था .. मैं देखूंगा कि क्या मैं इसे फिर से पा सकता हूं।
gbjbaanb

1
आप किस "ढेर" के बारे में बात कर रहे हैं? अधिकांश कचरा युवा पीढ़ी के स्तर पर पुन: प्राप्त किया जाता है, और अधिकांश प्रदर्शन लाभ उस कॉम्पैक्टीफिकेशन से बिल्कुल आ रहे हैं। बेशक, यह ज्यादातर कार्यात्मक प्रोग्रामिंग (कई लघु-जीवित छोटी वस्तुओं) के लिए विशिष्ट मेमोरी आवंटन प्रोफ़ाइल पर दिखाई देता है। और, ज़ाहिर है, ऐसे कई अनुकूलन अवसर हैं जो अभी तक काफी तलाश नहीं किए गए हैं - उदाहरण के लिए, एक गतिशील क्षेत्र विश्लेषण जो ढेर के आवंटन को ढेर या पूल आवंटन में स्वचालित रूप से बदल सकता है।
एसके-तर्क

3
मैं आपके दावे से असहमत हूं कि ढेर आवंटन 'स्टैक के रूप में तेज' है - हीप आवंटन के लिए थ्रेड सिंक्रोनाइजेशन की आवश्यकता होती है और स्टैक को (परिभाषा के अनुसार) नहीं
JBRWilkinson

1
मुझे ऐसा लगता है, लेकिन जावा और .net के साथ आप मेरी बात देखते हैं - आपको अगले फ्री ब्लॉक का पता लगाने के लिए ढेर नहीं चलना है, इसलिए उस संबंध में काफी तेज है, लेकिन हां - आप सही हैं, यह होना चाहिए लॉक जो थ्रेडेड ऐप्स को नुकसान पहुंचाएगा।
gbjbaanb

2

ईडन स्पेस

तो मेरा सवाल यह है कि क्या यह वास्तव में सच हो सकता है, और यदि ऐसा है तो जावा का ढेर इतनी तेजी से क्यों आवंटित किया गया है।

मैं इस बारे में थोड़ा अध्ययन कर रहा हूं कि जावा जीसी कैसे काम करता है क्योंकि यह मेरे लिए बहुत दिलचस्प है। मैं हमेशा सी और सी ++ में मेमोरी आवंटन रणनीतियों के अपने संग्रह का विस्तार करने की कोशिश कर रहा हूं (सी में कुछ इसी तरह को लागू करने की कोशिश में रुचि रखता हूं), और यह एक फट फैशन में बहुत सी वस्तुओं को आवंटित करने का एक बहुत तेज़ तरीका है व्यावहारिक दृष्टिकोण लेकिन मुख्य रूप से मल्टीथ्रेडिंग के कारण।

जिस तरह से जावा जीसी आवंटन कार्य करता है वह शुरू में "ईडन" अंतरिक्ष में वस्तुओं को आवंटित करने के लिए एक बेहद सस्ते आवंटन रणनीति का उपयोग करता है । मैं जो बता सकता हूं, वह एक अनुक्रमिक पूल आवंटनकर्ता का उपयोग कर रहा है।

एल्गोरिथ्म के मामले में यह पूरी तरह से तेज है और mallocसी या डिफॉल्ट में सामान्य प्रयोजन की तुलना में अनिवार्य पृष्ठ दोष को कम करना , operator newसी ++ में फेंकना है।

लेकिन अनुक्रमिक आवंटनकर्ताओं की एक कमजोर कमजोरी होती है: वे चर-आकार के विखंडू को आवंटित कर सकते हैं, लेकिन वे किसी भी व्यक्ति को विखंडित नहीं कर सकते। वे बस संरेखण के लिए पैडिंग के साथ एक सीधे अनुक्रमिक फैशन में आवंटित करते हैं, और केवल एक बार में आवंटित सभी मेमोरी को शुद्ध कर सकते हैं। वे डेटा संरचनाओं के निर्माण के लिए विशेष रूप से C और C ++ में उपयोगी होते हैं जिन्हें केवल खोज के पेड़ की तरह सम्मिलन और तत्वों को हटाने की आवश्यकता नहीं होती है, जिसे केवल एक प्रोग्राम शुरू होने पर केवल एक बार बनाया जाना चाहिए और फिर बार-बार खोजा जाता है या केवल नई कुंजियाँ जोड़ी जाती हैं ( कोई कुंजी नहीं निकाली गई)।

उनका उपयोग उन डेटा संरचनाओं के लिए भी किया जा सकता है जो तत्वों को निकालने की अनुमति देते हैं, लेकिन उन तत्वों को वास्तव में स्मृति से मुक्त नहीं किया जाएगा क्योंकि हम उन्हें व्यक्तिगत रूप से नहीं दे सकते हैं। अनुक्रमिक आवंटनकर्ता का उपयोग करने वाली ऐसी संरचना बस अधिक से अधिक मेमोरी का उपभोग करेगी, जब तक कि यह कुछ आस्थगित पास न हो जहां डेटा को एक अलग अनुक्रमिक आवंटनकर्ता का उपयोग करके एक ताजा, कॉम्पैक्ट कॉपी में कॉपी किया गया था (और कभी-कभी एक बहुत प्रभावी तकनीक होती है अगर एक निश्चित आवंटन जीता जाता है किसी कारण के लिए नहीं - बस सीधे क्रमिक रूप से डेटा संरचना की एक नई प्रति आवंटित करें और पुराने की सभी मेमोरी को डंप करें)।

संग्रह

जैसा कि ऊपर डेटा संरचना / अनुक्रमिक पूल उदाहरण में, यह एक बड़ी समस्या होगी यदि जावा जीसी ने केवल इस तरह से आवंटित किया, भले ही यह कई व्यक्तिगत विखंडू के फटने के आवंटन के लिए सुपर फास्ट है। यह सॉफ्टवेयर बंद होने तक कुछ भी मुफ्त नहीं कर सकेगा, जिस बिंदु पर यह सभी मेमोरी पूल को एक साथ मुफ्त (शुद्ध) कर सकता है।

इसलिए, इसके बजाय, एक एकल जीसी चक्र के बाद, "ईडन" अंतरिक्ष (क्रमिक रूप से आवंटित) में मौजूदा वस्तुओं के माध्यम से एक पास बनाया जाता है, और जिन्हें अभी भी संदर्भित किया जाता है, वे एक और सामान्य-उद्देश्य आवंटनकर्ता का उपयोग करके आवंटित किया जाता है जो अलग-अलग विखंडों से मुक्त करने में सक्षम होता है। अब जिन संदर्भों को संदर्भित नहीं किया जाता है, उन्हें केवल शुद्ध करने की प्रक्रिया में निपटाया जाएगा। तो मूल रूप से यह "ईडन अंतरिक्ष से वस्तुओं को कॉपी करें यदि वे अभी भी संदर्भित हैं, और फिर शुद्ध करें"।

यह आम तौर पर काफी महंगा होगा, इसलिए मूल रूप से सभी मेमोरी को आवंटित करने वाले धागे को रोकने के लिए एक अलग पृष्ठभूमि थ्रेड में किया जाता है।

एक बार मेमोरी को ईडन स्पेस से बाहर कॉपी किया जाता है और इस अधिक महंगी योजना का उपयोग करके आवंटित किया जाता है जो प्रारंभिक जीसी चक्र के बाद व्यक्तिगत चोंच को मुक्त कर सकता है, ऑब्जेक्ट एक अधिक निरंतर मेमोरी क्षेत्र में चले जाते हैं। यदि वे संदर्भित हो जाते हैं, तो उन व्यक्तिगत विखंडनों को बाद के GC चक्रों में मुक्त कर दिया जाता है।

गति

अतः, गंभीर रूप से कहें, तो यह कारण है कि जावा जीसी सीधे ढेर आवंटन में C या C ++ को बेहतर ढंग से बेहतर बना सकता है क्योंकि यह थ्रेड में सबसे सस्ती, पूरी तरह से डीजनरलाइज्ड आवंटन रणनीति का उपयोग कर रहा है जो मेमोरी आवंटित करने का अनुरोध करता है। तब यह अधिक महंगे काम को बचाता है जो हमें सामान्य रूप से एक mallocऔर थ्रेड के लिए सीधे-अप जैसे अधिक सामान्य आवंटनक का उपयोग करते समय करना होगा ।

इसलिए वैचारिक रूप से जीसी को वास्तव में और अधिक काम करना है, लेकिन यह धागे के पार वितरित कर रहा है ताकि पूरी लागत का भुगतान एक ही धागे से न हो। यह थ्रेड को मेमोरी को सुपर सस्ते करने के लिए आवंटित करने की अनुमति देता है, और फिर चीजों को ठीक से करने के लिए आवश्यक वास्तविक व्यय को स्थगित कर देता है ताकि व्यक्तिगत वस्तुओं को वास्तव में दूसरे धागे से मुक्त किया जा सके। C या C ++ में जब हम mallocया कॉल करते हैं operator new, तो हमें एक ही थ्रेड के भीतर पूरी लागत का भुगतान करना होता है।

यह मुख्य अंतर यह है, और क्यों जावा बहुत अच्छी तरह से मात सकता है सी या सी ++ के लिए सिर्फ भोली कॉल का उपयोग mallocया operator newव्यक्तिगत रूप से नन्हा मात्रा का एक समूह आवंटित करने के लिए। बेशक जीसी चक्र में किक करने पर आमतौर पर कुछ परमाणु संचालन और कुछ संभावित लॉकिंग होने जा रहे हैं, लेकिन यह शायद थोड़ा बहुत अनुकूलित है।

मूल रूप से सरल व्याख्या एक धागे में भारी लागत का भुगतान करने के लिए उकसाती है ( malloc) बनाम एक एकल धागे में सस्ती लागत का भुगतान करना और फिर दूसरे में भारी लागत का भुगतान करना जो समानांतर ( GC) में चल सकता है । एक नकारात्मक पहलू के रूप में, इस तरह से करने का अर्थ है कि आपको ऑब्जेक्ट के संदर्भ से ऑब्जेक्ट के लिए दो अप्रत्यक्ष की आवश्यकता होती है, क्योंकि आवंटनकर्ता को मौजूदा ऑब्जेक्ट संदर्भों को अमान्य किए बिना स्मृति को कॉपी / स्थानांतरित करने की अनुमति देने की आवश्यकता होती है, और एक बार मेमोरी खो जाने पर आप स्थानिक स्थान भी खो सकते हैं। "ईडन" अंतरिक्ष से बाहर चले गए।

अंतिम लेकिन कम से कम, तुलना थोड़ा अनुचित है क्योंकि C ++ कोड सामान्य रूप से ढेर पर व्यक्तिगत रूप से वस्तुओं का एक नाव लोड आवंटित नहीं करता है। Decent C ++ कोड सन्निहित ब्लॉकों में या ढेर पर कई तत्वों के लिए मेमोरी आवंटित करने के लिए जाता है। अगर यह मुफ्त की दुकान पर एक समय में एक छोटी वस्तुओं का एक बोट लोड आवंटित करता है, तो कोड चमकदार है।


0

यह सब निर्भर करता है कि कौन गति को मापता है, किस कार्यान्वयन की गति को मापता है, और क्या साबित करना चाहता है। और वे क्या तुलना करते हैं।

यदि आप अभी C ++ में आवंटन / डीलिंग करते हुए देखते हैं, तो आपके पास मॉलॉक में 1,000,000 कॉल, और 1,000,000 कॉल मुफ्त () हो सकते हैं। जावा में, आपके पास नए () के लिए 1,000,000 कॉल होंगे और एक लूप में चल रहे कचरा संग्रहकर्ता को 1,000,000 ऑब्जेक्ट मिलेंगे जो इसे मुफ्त कर सकते हैं। लूप फ्री () कॉल से तेज हो सकता है।

दूसरी ओर, मॉलॉक / मुक्त ने अन्य समय में सुधार किया है, और आम तौर पर मॉलोक / मुफ्त बस एक अलग डेटा संरचना में एक बिट सेट करता है, और एक ही धागे में मॉलोक / मुक्त होने के लिए अनुकूलित है, इसलिए एक बहुपरत वातावरण में कोई साझा स्मृति चर नहीं है कई मामलों में उपयोग किया जाता है (और लॉकिंग या साझा मेमोरी चर बहुत महंगे हैं)।

तीसरी ओर, संदर्भ गणना जैसी चीजें हैं जिन्हें आपको कचरा संग्रह के बिना आवश्यकता हो सकती है, और यह मुफ्त में नहीं आती है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.