2012-03-10 13 views
6

मैं कोड आवंटन के माध्यम से एकाधिक आवंटकों का उपयोग करने के लिए नए अधिभार को सरल बनाने से मेरी आवंटन विधि को स्विच करने का शोध कर रहा हूं। हालांकि, मैं कुशलतापूर्वक एकाधिक आवंटकों का उपयोग कैसे कर सकता हूं? मेरे शोध के माध्यम से मैं एकमात्र तरीका तैयार कर सकता था, आवंटकों को ग्लोबल्स होना था। हालांकि, ऐसा लगता है कि यह कई ग्लोबल्स का उपयोग करने के लिए आम तौर पर "बुरा विचार" है।कई आवंटकों का कुशलतापूर्वक उपयोग करना

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

+2

आवंटन को वैश्विक क्यों होना चाहिए? जब तक प्रत्येक आवंटित इकाई के अपने आवंटकों का संदर्भ होता है ताकि इसे सही ढंग से मुक्त किया जा सके, क्या इससे कोई फर्क नहीं पड़ता कि आवंटक वास्तव में कहां है? –

+0

आवंटित इकाई के लिए आवंटक कहां छोड़ देगा? ऐसा लगता है कि यह वैश्विक होना चाहिए। – chadb

उत्तर

8

सी ++ 2003 में आवंटक मॉडल टूटा हुआ है और वास्तव में कोई उचित समाधान नहीं है। सी ++ 2011 के लिए आवंटक मॉडल तय किया गया था और आपके पास प्रति आवंटित आवंटक हो सकते हैं जो निहित वस्तुओं तक प्रचारित होते हैं (जब तक, निश्चित रूप से, आप उन्हें प्रतिस्थापित करना नहीं चुनते)। आम तौर पर, इसके लिए उपयोगी होने के लिए आप शायद गतिशील रूप से पॉलीमोर्फिक आवंटक प्रकार का उपयोग करना चाहते हैं जो डिफ़ॉल्ट std::allocator<T> होने की आवश्यकता नहीं है (और आम तौर पर मैं अपेक्षा करता हूं कि यह गतिशील रूप से बहुरूप नहीं हो सकता है हालांकि यह बेहतर कार्यान्वयन विकल्प हो सकता है)। हालांकि, [लगभग] मानक सी ++ लाइब्रेरी में सभी कक्षाएं जो मेमोरी आवंटन करती हैं वे टेम्पलेट्स हैं जो आवंटक प्रकार को टेम्पलेट तर्क के रूप में लेते हैं (उदाहरण के लिए आईओएसट्रीम एक अपवाद है लेकिन आमतौर पर वे आवंटन समर्थन जोड़ने वाले वारंट को स्मृति की कोई भी रोचक राशि आवंटित नहीं करते हैं)।

आपकी कई टिप्पणियों में आप जोर दे रहे हैं कि आवंटकों को प्रभावी रूप से वैश्विक होने की आवश्यकता है: यह निश्चित रूप से सही नहीं है। प्रत्येक आवंटक-जागरूक प्रकार आवंटित आवंटक की एक प्रति संग्रहीत करता है (कम से कम, यदि उसके पास कोई आवृत्ति स्तर डेटा है; यदि ऐसा नहीं है तो स्टोर करने के लिए कुछ भी नहीं है उदाहरण के लिए operator new() और operator delete() का उपयोग कर डिफ़ॉल्ट आवंटक के साथ मामला) । इसका प्रभावी अर्थ यह है कि किसी ऑब्जेक्ट को दी गई आवंटन तंत्र को तब तक चिपकने की आवश्यकता होती है जब तक इसका उपयोग करने वाला कोई सक्रिय आवंटक न हो। यह वैश्विक ऑब्जेक्ट का उपयोग करके किया जा सकता है लेकिन यह भी उदाहरण का उपयोग करके किया जा सकता है। रेफरेंस गिनती या ऑब्जेक्टर्स को उस ऑब्जेक्ट के साथ संबद्ध करना जिसमें सभी ऑब्जेक्ट्स दिए गए हैं। उदाहरण के लिए, यदि प्रत्येक "दस्तावेज़" (एक्सएमएल, एक्सेल, पेज, जो भी संरचना फाइल सोचता है) अपने सदस्यों को एक आवंटक पास करता है, तो आवंटक दस्तावेज़ के सदस्य के रूप में रह सकता है और जब इसकी सभी सामग्री नष्ट हो जाती है तो दस्तावेज़ नष्ट हो जाता है । आवंटक मॉडल के इस भाग को पूर्व-सी ++ 2011 कक्षाओं के साथ काम करना चाहिए, जब तक कि वे एक आवंटन तर्क भी लेते हैं। हालांकि, पूर्व-सी ++ 2011 कक्षाओं में आवंटक निहित वस्तुओं को पारित नहीं किया जाएगा। उदाहरण के लिए, यदि आप std::vector<std::string> पर आवंटक देते हैं तो C++ 2011 संस्करण std::string एसपर आवंटित आवंटक का उपयोग करके std::string एस के साथ सौदा करने के लिए उचित रूप से परिवर्तित किया जाएगा।यह प्री-सी ++ 2011 आवंटकों के साथ नहीं होगा।

वास्तव में उपप्रणाली में आवंटकों का उपयोग करने के लिए आपको प्रभावी रूप से उन्हें अपने कार्यों और/या कक्षाओं के लिए तर्क के रूप में स्पष्ट रूप से पारित करने की आवश्यकता होगी या स्पष्ट रूप से आवंटक-जागरूक वस्तुओं के माध्यम से संदर्भ के रूप में कार्य किया जाएगा। उदाहरण के लिए, यदि आप संदर्भित किसी भी मानक कंटेनर का उपयोग [संदर्भ] के संदर्भ में करते हैं, तो आप get_allocator() विधि का उपयोग करके प्रयुक्त आवंटक प्राप्त कर सकते हैं।

+0

बहुत रोचक, मैंने संदर्भ गणना के बारे में सोचा नहीं था। चूंकि मैं अपना खुद का आवंटक बनाउंगा, तो क्या मुझे संदर्भ गणना के लिए अनुमति देने के लिए कमजोर_रफेर जैसे कुछ प्राप्त करना चाहिए? – chadb

+1

व्यक्तिगत रूप से, मैं एक आवंटक 'my_allocator' के सदस्य के रूप में' std :: shared_ptr 'का उपयोग करता हूं। वास्तविक आवंटन तर्क 'my_allocation_base' से प्राप्त कक्षाओं में स्थित होगा। यदि आपके पास केवल एक आवंटन दृष्टिकोण है, तो निश्चित रूप से, तर्क को वस्तु के प्रति सीधे तर्क में डाल दें। 'Weak_reference' का उपयोग करके (यह नहीं पता कि यह क्या है) लगता है जैसे यह काम नहीं करता है: आप आवंटित आवंटित स्मृति वाले प्रत्येक ऑब्जेक्ट से आवंटन ऑब्जेक्ट का वास्तविक संदर्भ रखना चाहते हैं और संदर्भ गणना को कम करने के बाद कम किया जाना चाहिए का विमोचन किया। –

2

आप new प्लेसमेंट का उपयोग कर सकते हैं। इसका उपयोग स्मृति क्षेत्र निर्दिष्ट करने के लिए या प्रकार के static void* operator new(ARGS) को अधिभारित करने के लिए किया जा सकता है। ग्लोबल्स की आवश्यकता नहीं है, और वास्तव में यहां एक बुरा विचार है, अगर दक्षता महत्वपूर्ण है और आपकी समस्याएं मांग रही हैं। आपको निश्चित रूप से एक या अधिक आवंटकों को पकड़ना होगा।

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

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

+0

आवंटकों को कैसे रखा जाना चाहिए? आपने बताया कि वे वैश्विक नहीं होना चाहिए, लेकिन तब कहां होना चाहिए? (इसके अलावा, मैं मानक कंटेनर के साथ संगतता से चिंतित नहीं हूं क्योंकि मेरे पास पहले से ही है)। – chadb

+0

@chadb यह समस्या पर निर्भर करता है। मैं दोनों सदस्य संदर्भ (उदा। संदर्भ गिनती आवंटन के साथ) और बाहरी संदर्भ (उदाहरण के लिए एक ग्राफ के लिए एक आवंटक जिसका उपयोग नोड्स एक आवंटक द्वारा प्रबंधित किया जाता है) का उपयोग करते हैं। थ्रेड स्थानीय आवंटकों (धागे या उसके डेटा द्वारा उपयोग) एक और दृष्टिकोण है, हालांकि मैंने उस मामले में बाहरी संदर्भ का पक्ष लिया है। – justin

+0

विशेष रूप से एक संपूर्ण उपप्रणाली के लिए उपयोग किए गए आवंटन के लिए क्या है (जिसका रूट सिंगलटन में नहीं है)? ऐसा लगता है कि फिलहाल मेरा प्राथमिक उपयोग मामला है, जैसा कि मैंने विश्वास किया है कि मैंने संरेखण पद में उल्लेख किया है। उस के लिए आवंटक कहाँ संग्रहित किया जाएगा? मैं वहां किसी भी मामले के अलावा किसी भी मामले के बारे में नहीं सोच सकता। – chadb

1

एकाधिक आवंटकों के लिए कुछ उपयोगों में कम CPU उपयोग, कम विखंडन, और कम कैश मिस शामिल हैं। तो समाधान वास्तव में इस बात पर निर्भर करता है कि आपका आवंटन बाधा किस प्रकार और कहां है।

सिंक्रनाइज़ेशन को समाप्त करने, सक्रिय थ्रेड के लिए लॉकलेस ढेर होने से CPU उपयोग में सुधार किया जाएगा। यह थ्रेड स्थानीय स्टोरेज के साथ आपकी मेमोरी आवंटक में किया जा सकता है।

अलग-अलग जीवनकाल के साथ आवंटन को अलग-अलग ढेर से आवंटित करके फ्रैगमेंटेशन में सुधार किया जाएगा - उपयोगकर्ताओं के सक्रिय कार्य से अलग ढेर में पृष्ठभूमि IO आवंटित करने से यह सुनिश्चित होगा कि दोनों एक-दूसरे को भ्रमित न करें। यह संभवतः आपके ढेर के लिए ढेर करके किया जाता है, और जब आप विभिन्न कार्यात्मक क्षेत्रों में होते हैं तो पुश/पॉपिंग करते हैं।

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

+0

शायद कुछ गलत व्याख्या, हालांकि, मेरा सवाल मुख्य रूप से एकाधिक आवंटकों का उपयोग कैसे किया गया था, क्यों नहीं। – chadb

संबंधित मुद्दे