2010-10-08 9 views
5

मुझे वास्तव में तंग और कठिन स्मृति सीमा के साथ समस्या है। मैं एक सीपीपी गीक हूं और मैं अपनी मेमोरी उपयोग को कम करना चाहता हूं। कृपया मुझे कुछ सुझाव दें।(सी ++) स्मृति उपयोग को कम करने के लिए युक्तियों की तलाश में


मेरे दोस्तों में से एक ने मेरे structs के अंदर कार्यों को लेने की सिफारिश की। उदाहरण के बजाय प्रयोग करने के लिए:

struct node{ 
    int f() 
    {} 
} 

वह सिफारिश मुझे इस्तेमाल करने:

int f(node x) 
{} 

यह वास्तव में मदद करता है?

नोट: मेरे पास मेरी संरचना की बहुत सारी प्रतियां हैं।

मैं एक ऑनलाइन न्यायाधीश पर एक अभ्यास समस्या के लिए खंड पेड़ के कुछ प्रकार कोडिंग कर रहा हूँ:


यहाँ कुछ अधिक जानकारी है। मुझे एक संरचना में पेड़ नोड्स मिलते हैं। मेरी संरचना में ये चर हैं:

int start; 
    int end; 
    bool flag; 
    node* left; 
    node* right; 

स्मृति सीमा 16 एमबी है और मैं 16.38 एमबी का उपयोग कर रहा हूं।

+2

आपका प्रोग्राम क्या करता है? यह किस एल्गोरिदम का उपयोग करता है? सामान्य शब्दों में अनुकूलन के बारे में बात करना मुश्किल है। –

+0

यदि आप लिनक्स पर हैं तो आप यह देखने के लिए valgrind/massif का उपयोग कर सकते हैं कि आपका ढेर कहाँ जा रहा है – pm100

+7

नि: शुल्क कार्यों के साथ सदस्य फ़ंक्शंस को प्रतिस्थापित करना कोड के आकार को थोड़ा सा प्रभावित नहीं करेगा। हालांकि, यह संदर्भ के बजाय मूल्य से गुजरने जैसी गलतियों को आसान बना देगा। –

उत्तर

9

नहीं, नियमित सदस्य कार्य कक्षा या संरचना को बड़ा नहीं बनाते हैं। आभासी फ़ंक्शन (कई प्लेटफ़ॉर्म पर) को कक्षा में vtable पॉइंटर जोड़ना शुरू कर सकता है। X86 पर जो आकार को चार बाइट्स से बढ़ाएगा। वर्चुअल फ़ंक्शन जोड़ते समय कोई और मेमोरी आवश्यक नहीं होगी, हालांकि - एक पॉइंटर पर्याप्त है। किसी वर्ग या संरचना प्रकार का आकार कभी शून्य नहीं होता है (भले ही इसमें कोई सदस्य चर या वर्चुअल फ़ंक्शन हों)। यह सुनिश्चित करना है कि प्रत्येक इंस्टेंस में अपनी मेमोरी स्पेस (source, सेक्शन 9.0.3) पर कब्जा हो।

+0

धन्यवाद। और क्या आपके पास कोई सुझाव है? – user12345

+0

उपयोगकर्ता 12345: ऐसा नहीं है, क्योंकि निक मेयर ने आपकी पोस्ट पर एक टिप्पणी में बताया, सामान्य रूप से स्मृति उपयोग अनुकूलन पर चर्चा करना मुश्किल है। आपको ज्यादा केंद्रित होने की ज़रूरत है। –

+0

वैसे भी धन्यवाद। यह एक बड़ी मदद थी। – user12345

0

आप कुछ अनुकूलन करने के लिए संकलन झंडे का उपयोग कर सकते हैं। आप जी उपयोग कर रहे हैं ++ आप के साथ परीक्षण कर सकते हैं:

C++ Optimization Techniques

Should we still be optimizing "in the small"?

Constants and compiler optimization in C++

What are the known C/C++ optimizations for GCC

+0

दुर्भाग्य से न्यायाधीश इसे संकलित करता है, न कि मुझे! – user12345

+1

@ user12345 आपको उस जानकारी को प्रश्न में जोड़ना चाहिए। – karlphillip

+1

न्यायाधीश? क्या आप प्रोग्रामिंग प्रतियोगिता कर रहे हैं? क्या आप समस्या के बारे में विवरण दे सकते हैं? यदि आप स्मृति सीमा तक पहुंच गए हैं तो आपका एल्गोरिदम संभवतः अच्छा नहीं है। –

5

: -O2

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

21

मैं आपके प्रश्न के सबटेक्स्ट द्वारा अनुमान लगा रहा हूं कि आपके अधिकांश मेमोरी उपयोग डेटा हैं, कोड नहीं। यहां कुछ युक्तियां दी गई हैं:

  • यदि आपकी डेटा सीमाएं सीमित हैं, तो इसका लाभ उठाएं। यदि एक पूर्णांक की श्रेणी -128 से 127 है, तो int के बजाय char का उपयोग करें, या unsigned char यदि यह 0 से 255 है।इसी प्रकार -32768..32767 और 0..65535 की श्रेणियों के लिए int16_t या uint16_t का उपयोग करें।
  • संरचना तत्वों का पुनर्व्यवस्थित करें ताकि बड़ी वस्तुएं पहले आ सकें, ताकि डेटा संरेखण संरचना के बीच में मृत स्थान को न छोड़ सके। आप आमतौर पर कंपाइलर विकल्पों के माध्यम से पैडिंग को नियंत्रित भी कर सकते हैं, लेकिन यह लेआउट को पहले स्थान पर इष्टतम बनाने के लिए बेहतर है।
  • कंटेनरों का उपयोग करें जिनके पास बहुत अधिक ओवरहेड नहीं है। उदाहरण के लिए list के बजाय vector का उपयोग करें। std::vector के बजाय boost::ptr_vector का उपयोग करें shared_ptr
  • आभासी तरीकों से बचें। एक स्ट्रक्चर या क्लास में जो पहली आभासी विधि आप जोड़ते हैं वह एक छिपे हुए पॉइंटर को एक vtable में जोड़ती है।
+0

जोड़ दी है यह एक बहुत मददगार थी। धन्यवाद – user12345

0

दो संभावनाएं सब बराबर नहीं हैं:

  • पहले में, f()node के एक सदस्य कार्य है।
  • दूसरे में, f() एक नि: शुल्क (या नामस्थान-स्कोप) फ़ंक्शन है। (यह भी ध्यान दें कि दो f() के हस्ताक्षर अलग हैं।)

अब ध्यान दें कि, पहली शैली में, f() एक inline सदस्य कार्य है। कक्षा निकाय के अंदर एक सदस्य समारोह को परिभाषित करना इसे इनलाइन बनाता है। हालांकि इनलाइनिंग गारंटी नहीं है, यह संकलक के लिए सिर्फ एक संकेत है। छोटे निकायों के साथ कार्यों के लिए, उन्हें इनलाइन करना अच्छा हो सकता है, क्योंकि यह सिर पर फ़ंक्शन कॉल से बच जाएगा। हालांकि, मैंने कभी ऐसा नहीं देखा है कि मेक-एंड-ब्रेक कारक बनें।

आप नहीं चाहते हैं या यदि f() इनलाइन किए जाने वाले की पात्रता नहीं है, तो आप इसे वर्ग शरीर (शायद एक .cpp फ़ाइल में) के बाहर के रूप में परिभाषित करना चाहिए:

int node::f() { /* stuff here */ } 

तो स्मृति के उपयोग में एक समस्या है आपका कोड, तो शायद उपरोक्त विषय प्रासंगिक नहीं हैं। निम्नलिखित का अन्वेषण आपको कुछ संकेत दे सकता है

  • अपने कार्यक्रम में सभी कक्षाओं के आकार खोजें। इस जानकारी को खोजने के लिए sizeof का उपयोग करें, उदा। sizeof (नोड)
  • पता लगाएं कि आपका प्रोग्राम कौन सा वर्ग बना रहा है, इसकी अधिकतम संख्या क्या है।
  • सूचना के ऊपर दो श्रृंखला का उपयोग करना, अपने कार्यक्रम से

    सबसे बुरे मामले स्मृति उपयोग = n1 * sizeof (node1) + n2 * sizeof (node2) + ... सबसे खराब स्थिति स्मृति के उपयोग का अनुमान

  • वर्गों के अधिकतम उदाहरणों की संख्या कम:

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

  • प्रत्येक कक्षा के आकार को कम करें। हालांकि यह आपके नियंत्रण में है।

कक्षाओं के आकार को कैसे कम किया जाए? packing से बचने के लिए कक्षा के सदस्यों को संकुचित रूप से पैक करने का प्रयास करें।

0

जैसा कि अन्य ने कहा है, विधियों में संरचना के आकार में वृद्धि नहीं होती है जब तक कि उनमें से कोई वर्चुअल नहीं है।

आप डेटा को प्रभावी ढंग से संपीड़ित करने के लिए बिटफील्ड का उपयोग कर सकते हैं (यह आपके बूलियन के साथ विशेष रूप से प्रभावी है ...)। इसके अलावा, आप कुछ बाइट्स को बचाने के लिए पॉइंटर्स के बजाय इंडेक्स का उपयोग कर सकते हैं।

मेमोरी प्रबंधन ओवरहेड से बचने के लिए अलग-अलग (उदा।, नए [] का उपयोग करके, नियमित रूप से नए बार नहीं) के बजाय बड़े नोड्स में अपने नोड आवंटित करना याद रखें।

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

इन सबसे ऊपर, एक अलग एल्गोरिथ्म खोजने खेल पूरी तरह से बदल सकते हैं ...

1

अपने अंतिम उदाहरण (पेड़), आप XOR के साथ एक चालाक हैक उपयोग कर सकते हैं एक एकल नोड के साथ दो नोड संकेत बदलने के लिए के लिए सूचक, जैसा वर्णन here है। यह केवल तभी काम करता है जब आप सही क्रम में पेड़ को पार करते हैं। जाहिर है, यह कोड पठनीयता को नुकसान पहुंचाता है, इसलिए अंतिम उपाय का होना चाहिए।

+0

उस लिंक के लिए धन्यवाद .. दिलचस्प चीजें, इच्छा है कि मैंने इसके बारे में सोचा था जब मैं बहुत, बहुत तंग स्मृति बाधाओं w/एम्बेडेड सिस्टम के लिए कोडिंग कर रहा था। –

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