2012-05-17 8 views
9

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

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

मैं कोड समीक्षा या चर्चाओं के दौरान बहुत कुछ देख रहा हूं, कि स्मृति विखंडन पहली चीजों में से एक है। ऐसा लगता है कि अब इसके बारे में बहुत बड़ा डर है, और समय से पहले "विखंडन को रोकने" की एक बड़ी पहल है। कोड परिवर्तनों का अनुरोध किया जाता है जो स्मृति विखंडन समस्याओं को कम करने या रोकने के लिए अनुकूल लगते हैं। मैं बल्ले से इन अधिकारों से असहमत हूं क्योंकि वे मेरे लिए समयपूर्व अनुकूलन की तरह लगते हैं। मैं कोड सफाई/पठनीयता/रखरखाव/आदि बलिदान होगा। इन परिवर्तनों को पूरा करने के लिए।

उदाहरण के लिए, निम्न कोड ले:

std::stringstream s; 
s << "This" << "Is" << "a" << "string"; 

ऊपर, आवंटन की संख्या stringstream यहाँ बनाता अपरिभाषित है, यह 4 आवंटन, या सिर्फ 1 आवंटन हो सकता है। इसलिए हम उस अकेले के आधार पर अनुकूलित नहीं कर सकते हैं, लेकिन आम सहमति आम तौर पर एक निश्चित बफर का उपयोग करना है या किसी भी तरह से कम आवंटन का संभावित रूप से उपयोग करने के लिए कोड को संशोधित करना है। मैं वास्तव में स्ट्रिंगस्ट्रीम को स्मृति समस्याओं में भारी योगदानकर्ता के रूप में विस्तारित नहीं करता हूं, लेकिन शायद मैं गलत हूं।

जनरल सुधार कोड के लिए सुझाव ऊपर की तर्ज पर कर रहे हैं:

std::stringstream s; 
s << "This is a string"; // Combine it all to 1 line, supposedly less allocations? 

भी एक विशाल धक्का जहां कभी संभव ढेर के ऊपर ढेर उपयोग करने के लिए नहीं है।

क्या इस तरह मेमोरी विखंडन के बारे में पूर्ववत होना संभव है, या क्या यह केवल सुरक्षा की झूठी भावना है?

+4

मुझे लगता है कि न्याय करने का एक आसान तरीका यह है: आप कार्यक्रमों में दो चीजों की चिंता करते हैं: कार्यान्वयन शुद्धता और कार्यान्वयन दक्षता। हम सभी दोनों श्रेणियों में उच्चतम चाहते हैं, लेकिन व्यावहारिक रूप से यह दक्षता पर शुद्धता पर ध्यान केंद्रित करना बेहतर है, क्योंकि दुनिया में सबसे कुशल गलत कार्यक्रम अभी भी गलत है, और अभी भी बेकार है। आपको दोनों अपनी योग्यता पर ध्यान केंद्रित करना चाहिए; * समयपूर्व अनुकूलन का अर्थ केवल शुद्धता * की तुलना में दक्षता पर अधिक ध्यान केंद्रित करना है। यदि आपके पास शुद्धता बलिदान के बिना इसे कुशल बनाने की क्षमता है, तो आपको निश्चित रूप से ऐसा करना चाहिए! – GManNickG

+3

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

उत्तर

14

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

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

+0

एक गेम डेवलपर के रूप में, कस्टम आवंटकों और पूल बहुत आम हैं, और हम आम तौर पर शुरुआत से ही उन्हें बनाते हैं। जब आप जानते हैं कि आपको उनकी आवश्यकता नहीं होगी, इसका कोई कारण नहीं है। विभिन्न उपप्रणाली के बजट निर्धारित करते समय यह चीजों को और भी आसान बनाता है। –

+0

मुझे लगता है कि यहां आम सहमति है कि क्योंकि हम मानते हैं कि विखंडन पहले से ही एक मुद्दा है, भविष्य के आवंटन इस मुद्दे को बढ़ाते हैं। उस संबंध में, उन्हें लगता है कि अनुकूलन "अंधाधुंध" नहीं बनाया गया है, हालांकि मुझे विश्वास है कि प्रत्येक मामले संदर्भ विशिष्ट है और विखंडन के मुद्दों का अस्तित्व भावी आवंटन के लिए प्रासंगिक नहीं हो सकता है। आपके क्या विचार हैं? –

+0

@RobertDailey: आप अभी भी यह जानना चाहते हैं कि कौन से आवंटन वास्तव में विखंडन का कारण बन रहे हैं। इस बात पर विश्वास करने का कोई कारण नहीं है कि यादृच्छिक अतिरिक्त आवंटन एक्स अंतर का एक टुकड़ा बना देगा- जैसे कि आप एक यादृच्छिक फ़ंक्शन एक्स जोड़ते हैं और इसे एक बार कॉल करते हैं, भले ही आप पहले ही सीपीयू बाध्य हों, यह अप्रासंगिक होगा। – Puppy

1

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

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

6

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

मैं भी चिंतित हूं कि बहुत से सुझाव हैं जो केवल सादे गलत हैं। संभवत: 1/2 चीजें जो लोग आम तौर पर कहते हैं उन्हें "स्मृति विखंडन से बचने के लिए" किया जाना चाहिए, संभवतया कोई प्रभाव नहीं पड़ता है और शेष का एक बड़ा हिस्सा हानिकारक होता है।

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

+0

आपकी दूसरी टिप्पणी बहुत महत्वपूर्ण है। विखंडन का कारण हमेशा स्पष्ट नहीं होता है, न ही समाधान है। –

-3

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

विखंडन के संबंध में, विभिन्न प्रकार की वस्तुओं के लिए कुछ प्रकार के भंडारण आवंटित करने का प्रयास करें और उन्हें अपने कोड में yourslef प्रबंधित करें।

यानी यदि आपने 5 प्रकार की वस्तुओं (कक्षा ए, बी, सी, डी और ई) कहा है। आप शुरुआत में अंतरिक्ष आवंटित कर सकते हैं कहने के लिए प्रत्येक प्रकार की 1000 वस्तुओं को कैशए, कैशबी ... कैशई में कहें।

तो, आप मॉलोक और नई के साथ-साथ विखंडन की कई कॉल से बचेंगे। इसके अलावा कोड पहले के रूप में पठनीय होगा, क्योंकि आपको केवल myAlloc जैसे कुछ को लागू करने की आवश्यकता है, जो आपके कैशए, कैशब आदि से आवंटित होगा ...

1

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

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

0

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

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

मुझे आंतरिक डिजाइन के बारे में क्या याद है, थ्रेडिंग बिल्डिंग ब्लॉक स्केलेबल आवंटक दोनों को स्मृति आवंटन स्केलेबिलिटी बढ़ाने और स्मृति विखंडन को कम करने की कोशिश की जा सकती है।

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

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