2010-07-06 27 views
39

जब हम मेमोरी आवंटित करने के लिए malloc() का उपयोग करते हैं, तो क्या हमें आकार दो आकार में देना चाहिए? या हम सिर्फ सटीक आकार देते हैं जिसकी हमें आवश्यकता है?
क्या दो की शक्ति में स्मृति आवंटित करना बेहतर है?

//char *ptr= malloc(200); 
char *ptr= malloc(256);//instead of 200 we use 256 

यदि यह आकार जो दो की शक्ति में है देने के लिए बेहतर है की तरह, उस के लिए क्या कारण है? यह बेहतर क्यों है?

धन्यवाद

संपादित

मेरी भ्रम का कारण जोएल के ब्लॉग से बोली पीछा कर रहा है Back to Basics

स्मार्ट प्रोग्रामर की हमेशा आवंटन ब्लॉक से malloc की संभावित distruption को कम मेमोरी जो कि आकार में 2 की शक्तियां हैं। तुम्हें पता है , 4 बाइट, 8 बाइट्स, 16 बाइट्स, 18446744073709551616 बाइट्स, आदि कारण है कि जो कोई लेगो के साथ खेलता है करने के लिए सहज ज्ञान युक्त होना चाहिए के लिए, यह अजीब विखंडन की मात्रा को मुक्त में पर चला जाता है कम से कम श्रृंखला। यद्यपि यह कचरे की जगह जैसा प्रतीत हो सकता है, यह को देखना भी आसान है, यह अंतरिक्ष को 50% से अधिक कैसे बर्बाद नहीं करता है। तो आपका प्रोग्राम का उपयोग दो गुना अधिक स्मृति से अधिक नहीं करता है क्योंकि की आवश्यकता है, जो कि सौदा बड़ा नहीं है।

क्षमा करें, मुझे पहले उपरोक्त उद्धरण पोस्ट करना चाहिए था। मैं क्षमाप्रार्थी हूं!

अधिकतर जवाब, अब तक कहते हैं कि दो की शक्ति में स्मृति आवंटित करना एक बुरा विचार है, फिर किस परिदृश्य में जोएल के बिंदु malloc() का पालन करना बेहतर होगा? उसने ऐसा क्यों कहा? क्या ऊपर उद्धृत सुझाव अब अप्रचलित है?

कृपया इसे समझाएं।
धन्यवाद

+3

यह बेहतर नहीं है। यह स्मृति बर्बाद करता है। – Adrian

+1

मेरा अनुमान है कि कुछ प्लेटफॉर्म पर, malloc() पृष्ठ आवंटन आवंटन न्यूनतम आवंटन-आकार के साथ कर सकता है।मैंने इसे और अधिक नहीं देखा है, लेकिन मुझे पता है कि कई कस्टम मेमोरी कार्यान्वयन यह करते हैं। – Simon

उत्तर

50

बस आपको आवश्यक सटीक आकार दें। एकमात्र कारण यह है कि दो आकार का एक शक्ति "बेहतर" हो सकता है ताकि त्वरित आवंटन और/या स्मृति विखंडन से बच सकें।

हालांकि, कोई भी गैर-तुच्छ malloc कार्यान्वयन जो स्वयं को कुशल होने के साथ चिंतित करता है आंतरिक रूप से इस तरह से आवंटन के दौर में होगा यदि ऐसा करने के लिए उचित हो। आपको "मदद" मॉलोक के साथ खुद को चिंता करने की आवश्यकता नहीं है; मॉलोक अपने आप ठीक कर सकते हैं।

संपादित करें:

सॉफ्टवेयर लेख पर जोएल की अपनी बोली के जवाब में, उस अनुभाग में जोएल के बिंदु (जो सही ढंग से संदर्भ कि पैरा है कि आप उद्धृत इस प्रकार के बिना विचार करने के लिए कठिन है) कि अगर है आप अक्सर पुनः-बफर आवंटित करने की अपेक्षा कर रहे हैं, इसलिए additively के बजाय, गुणात्मक रूप से ऐसा करना बेहतर है। वास्तव में, वास्तव में, C12+ (दूसरों के बीच) में std::string और std::vector कक्षाएं क्या करती हैं।

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

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

वह गुजरने में उल्लेख करता है कि इससे "मुक्त श्रृंखला में विखंडन" को कम करने में मदद मिलती है, लेकिन इसका कारण उनके सटीक आकार के बजाय आवंटन की संख्या और समानता के कारण अधिक है। एक बात के लिए, जितनी बार आप आवंटित करते हैं और स्मृति को हटा देते हैं, उतना ही अधिक आप ढेर को तोड़ने की संभावना रखते हैं, इससे कोई फर्क नहीं पड़ता कि आप किस आकार को आवंटित कर रहे हैं। दूसरा, यदि आपके पास एकाधिक बफर हैं जो आप एक ही गुणक आकार बदलने वाले एल्गोरिदम का उपयोग करके गतिशील रूप से आकार बदल रहे हैं, तो यह संभावना है कि यदि कोई 32 से 64 का आकार बदलता है, और दूसरा 16 से 32 का आकार बदलता है, तो दूसरा का पुनर्वसन सही हो सकता है जहां पहला हुआ करता था। यह मामला नहीं होगा यदि कोई 25 से 60 का आकार बदलता है और दूसरा 16 से 26 हो जाता है।

और फिर, वह जो भी बात कर रहा है उसके बारे में कोई भी लागू नहीं होता है यदि आप आवंटन चरण केवल एक बार करने जा रहे हैं ।

+0

तो इसका मतलब है कि 2 की शक्ति में आवंटन केवल उन मामलों के लिए है जब हमें स्मृति आवंटन प्रक्रिया पर समय बचाने के लिए समय की आवश्यकता होती है। ऐसा तब हो सकता है जब हमें स्मृति को आवंटित/आवंटित करने की आवश्यकता हो। अन्यथा, हमें सटीक राशि आवंटित करके स्थान बचाने को प्राथमिकता देना चाहिए। क्या मेरी समझ सही है? आपके विस्तृत उत्तर के लिए धन्यवाद। –

+1

हाँ, मैं कहूंगा कि यह एक बहुत अच्छा पाचन है। जब आप एक छोटी या निश्चित संख्या आवंटित करने जा रहे हैं, तो बस मॉलोक को बताएं कि आप वास्तव में क्या चाहते हैं। आपका प्रोग्राम अधिक पठनीय होगा, और मॉलोक ढेर विखंडन मुद्दे को आपके से बेहतर तरीके से संभालने में सक्षम होगा। –

+2

आपको यह मिला। उदाहरण के लिए, यदि आप अपने आप का एक स्टैक कार्यान्वयन लिखना चाहते थे, तो आप आंतरिक रूप से उस आवंटित स्मृति को बढ़ाएंगे जब केवल स्टैक पर धकेल गए आइटमों की संख्या आपके पास मौजूद स्थान की मात्रा से अधिक हो। इस मामले में, समय बचाने के लिए, जब भी आप अपनी सीमा को दबाते हैं तो आप स्टैक में आवंटित स्थान को दोगुना कर देंगे। यह एक अच्छा विचार है क्योंकि यदि आपने उस अतिरिक्त आइटम के लिए बस पर्याप्त जगह आवंटित की है, तो आपको * प्रत्येक * समय (जो महंगा और अनावश्यक है) करना होगा। – Tyler

6

यह एक बार सच हो गया है, लेकिन यह निश्चित रूप से बेहतर नहीं है।

बस आपको जिस मेमोरी की आवश्यकता है, उसे आवंटित करें, जैसे ही आप इसे पूरा कर लें और इसे समाप्त कर दें।

संसाधनों के साथ लाभप्रद हैं जो बहुत से प्रोग्राम हैं - उनमें से एक को न बनाएं।

1

यहके कार्यान्वयन libc पर पूरी तरह से निर्भर है। यह उस क्रियान्वयन पर निर्भर करता है जो ढेर हिस्सों को आरक्षित करने के लिए उपयुक्त होता है।

प्रश्न का उत्तर देने के लिए - नहीं, यह "बेहतर" नहीं है (यहां "बेहतर" से आपका मतलब है ...?)। यदि आप जिस आकार के लिए पूछते हैं वह बहुत छोटा है, malloc(3) आंतरिक रूप से बड़ा हिस्सा आरक्षित करेगा, तो बस अपने सटीक आकार के साथ चिपके रहें।

4

यह कुछ हद तक अप्रासंगिक है।

मॉलोक वास्तव में आपके अनुरोध के मुकाबले थोड़ी अधिक स्मृति आवंटित करता है, क्योंकि इसका निपटारा करने के लिए इसका मुख्य हेडर होता है। इसलिए इष्टतम भंडारण शायद 4k-12 बाइट्स जैसा कुछ है ... लेकिन यह कार्यान्वयन के आधार पर भिन्न होता है।

किसी भी मामले में, ऑप्टिमाइज़ेशन तकनीक के रूप में आपको अधिक संग्रहण करने के लिए कोई कारण नहीं है।

+0

स्पष्ट करने के लिए संपादित करें। अगर आपको यह पसंद नहीं है तो कृपया वापस करें :) –

2

आप प्रोसेसर के शब्द आकार के संदर्भ में स्मृति आवंटित करना चाहते हैं; 2 की पुरानी शक्ति नहीं होगी।

यदि प्रोसेसर में 32-बिट शब्द (4 बाइट्स) है, तो 4 बाइट्स की इकाइयों में आवंटित करें। प्रोसेसर डेटा को 4 बाइट सीमा पर शुरू करने के लिए पसंद करता है क्योंकि 2 बाइट्स के मामले में आवंटन सहायक नहीं हो सकता है।

दूसरी ओर, यह एक माइक्रो-अनुकूलन हो सकता है। अधिकांश मेमोरी आवंटन पुस्तकालयों को स्मृति को वापस करने के लिए सेट किया जाता है जो सही स्थिति पर गठबंधन होता है और कम से कम विखंडन छोड़ देगा। यदि आप 15 बाइट आवंटित करते हैं, तो लाइब्रेरी पैड आउट हो सकती है और 16 बाइट आवंटित कर सकती है। कुछ स्मृति आवंटकों के आवंटन आकार के आधार पर अलग-अलग पूल होते हैं।

संक्षेप में, आपको आवश्यक स्मृति की मात्रा आवंटित करें। आबंटन लाइब्रेरी/मैनेजर को आपके लिए वास्तविक राशि को संभालने दें। इन छोटे मुद्दों के बारे में चिंता से अधिक ऊर्जा को शुद्धता और मजबूती में रखें।

1

आज की स्मृति और इसकी गति के साथ मुझे नहीं लगता कि यह अब प्रासंगिक है।

इसके अलावा, यदि आप अक्सर स्मृति आवंटित करने वाले हैं तो आप कस्टम मेमोरी पूलिंग/प्री-आवंटन पर बेहतर विचार करेंगे।

1

वहाँ हमेशा परीक्षण कर रहा है ...

आप एक "नमूना" कार्यक्रम है कि एक पाश में स्मृति आवंटित की कोशिश कर सकते हैं। इस तरह आप देख सकते हैं कि आपका कंपाइलर जादुई रूप से 2 की शक्तियों में स्मृति आवंटित करता है। उस जानकारी के साथ, आप 2 रणनीतियों का उपयोग करके कुल स्मृति की समान राशि आवंटित करने का प्रयास कर सकते हैं: यादृच्छिक आकार के ब्लॉक और 2 आकार के ब्लॉक की शक्ति।

हालांकि बड़ी मात्रा में स्मृति के लिए मैं केवल अंतर, यदि कोई हो, की अपेक्षा करता हूं।

0

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

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

समयपूर्व अनुकूलन सभी बुराइयों की जड़ है।

18

बस डेविल्स एडवोकेट खेलने के लिए है, तो यहां Qt यह करता है:

मान लेते हैं कि हम QString स्ट्रिंग के लिए 15000 वर्ण संलग्न करते हैं।तब निम्नलिखित 18 reallocations ( एक संभव 15000 में से) होते हैं, जब रन स्थान से बाहर QString: 6132 4, 8, 12, 16, 20, 52, 116, 244, 500, 1012, 2036, 4084, , 8180, 10228, 12276, 14324, 16372. अंत में, क्यूस्ट्रिंग में 16372 यूनिकोड वर्ण आवंटित किए गए हैं, जिनमें से 15000 पर कब्जा कर लिया गया है।

मूल्यों ऊपर थोड़ा अजीब लग सकता है, लेकिन यहाँ मार्गदर्शक सिद्धांतों रहे हैं:

QString एक समय जब तक यह आकार 20 तक पहुँच जाता है 20 4084 तक में 4 अक्षर आबंटित करता है, यह दोगुना से अग्रिम प्रत्येक बार आकार। दरअसल, यह दो, शून्य से 12 वर्ष की अगले सत्ता में अग्रिमों (कुछ स्मृति allocators सबसे खराब प्रदर्शन है जब दो की सटीक शक्तियों का अनुरोध किया, क्योंकि वे किताब रखने के लिए प्रति ब्लॉक में कुछ बाइट्स का उपयोग करें।) 4084 से, यह 2048 वर्णों (4096 बाइट्स) के ब्लॉक से आगे बढ़ता है। यह समझ में आता है क्योंकि आधुनिक ऑपरेटिंग सिस्टम बफर को पुन: आवंटित करते समय पूरे डेटा की प्रतिलिपि नहीं बनाते हैं; भौतिक स्मृति पृष्ठ बस पुन: व्यवस्थित हैं, और केवल पर डेटा पहले और अंतिम पृष्ठों को वास्तव में की प्रतिलिपि बनाने की आवश्यकता है।

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

+0

+1 आपके उद्धरण में बोल्ड स्निपेट के लिए। लेकिन अगर आप कभी अंतर देखना चाहते हैं तो मुझे आश्चर्य होगा। –

+8

ऑफ-विषय, लेकिन मुझे लगता है कि यूनिकोड 2.0 के कुछ साल बाद, 16-बिट Wchar प्रकार चुनने की गलती करने वाले लोगों ने अभी भी एक यूटीएफ -16 कोड इकाई को यूनिकोड "चरित्र" कहा है ... –

0

आपको फिर से आवंटित होने पर malloc() के बजाय realloc() का उपयोग करना चाहिए। http://www.cplusplus.com/reference/clibrary/cstdlib/realloc/

हमेशा दो की शक्ति का उपयोग करें? यह इस बात पर निर्भर करता है कि आपका प्रोग्राम क्या कर रहा है। यदि आपको दो की शक्ति में बढ़ने पर आपकी पूरी डेटा संरचना को पुन: प्रसंस्करण करने की आवश्यकता है, तो हाँ यह समझ में आता है। अन्यथा, बस आपको जो चाहिए उसे आवंटित करें और स्मृति को हॉग न करें।

2

जब मैं एक बफर आवंटित कर रहा हूं जिसे अभी तक अज्ञात आकार के डेटा को समायोजित करने के लिए बढ़ने की आवश्यकता हो सकती है, तो मैं 2 शून्य 1 की शक्ति से शुरू होता हूं, और हर बार जब यह अंतरिक्ष से बाहर हो जाता है, तो मैं फिर से चलाता हूं पिछले आकार के साथ दो बार प्लस 1. यह ऐसा करता है इसलिए मुझे पूर्णांक ओवरफ्लो के बारे में चिंता करने की ज़रूरत नहीं है; आकार केवल ओवरफ्लो हो सकता है जब पिछला आकार SIZE_MAX था, जिस बिंदु पर आवंटन पहले ही विफल हो गया था, और 2*SIZE_MAX+1 == SIZE_MAX वैसे भी।

इसके विपरीत, अगर मैंने केवल 2 की शक्ति का उपयोग किया और इसे हर बार दोगुना कर दिया, तो मुझे सफलतापूर्वक 2^31 बाइट बफर मिल सकता है और फिर आकार को दोगुना करने के बाद अगली बार 0 बाइट बफर में फिर से स्थानांतरित हो सकता है।

जैसा कि कुछ लोगों ने कुछ मॉलोक कार्यान्वयन के लिए अच्छा होने के लिए 2-मिनट -12 के बारे में टिप्पणी की है, कोई भी 2 शून्य 12 की शक्ति के साथ समान रूप से शुरू हो सकता है, फिर इसे दोहराएं और प्रत्येक चरण में 12 जोड़ें ...

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

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