स्मृति विखंडन क्या है?


203

मैंने C ++ डायनामिक मेमोरी एलोकेशन के संदर्भ में "मेमोरी फ़्रेग्मेंटेशन" शब्द का कुछ बार इस्तेमाल किया है। स्मृति विखंडन से कैसे निपटा जाए, इसके बारे में मुझे कुछ प्रश्न मिले हैं, लेकिन एक ऐसा सीधा प्रश्न नहीं मिल सकता है जो इसके साथ संबंधित हो। इसलिए:

  • स्मृति विखंडन क्या है?
  • मैं कैसे बता सकता हूं कि स्मृति विखंडन मेरे आवेदन के लिए एक समस्या है? किस तरह के कार्यक्रम में सबसे अधिक नुकसान होने की संभावना है?
  • स्मृति विखंडन से निपटने के लिए अच्छे सामान्य तरीके क्या हैं?

इसके अलावा:

  • मैंने सुना है कि डायनेमिक एलोकेशन का इस्तेमाल करने से मेमोरी फ्रैगमेंटेशन बढ़ सकता है। क्या ये सच है? C ++ के संदर्भ में, मैं समझता हूं कि सभी मानक कंटेनर (std :: string, std :: वेक्टर, आदि) गतिशील मेमोरी आवंटन का उपयोग करते हैं। यदि इनका उपयोग पूरे कार्यक्रम में किया जाता है (विशेषकर std :: string), तो क्या मेमोरी विखंडन की समस्या होने की अधिक संभावना है?
  • मेमोरी विखंडन को एसटीएल-भारी एप्लिकेशन से कैसे निपटा जा सकता है?

1
बहुत बढ़िया जवाब, सभी को धन्यवाद!
AshleysBrain 16:22

4
पहले से ही बहुत सारे शानदार उत्तर हैं, लेकिन यहाँ एक वास्तविक एप्लिकेशन (फ़ायरफ़ॉक्स) से कुछ तस्वीरें हैं जहाँ मेमोरी विखंडन एक बड़ी समस्या थी: blog.pavlov.net/2007/11/10/memory-fragmentation
Marius Gedminas

2
@MariusGedminas लिंक किसी भी अधिक काम नहीं करता है यही कारण है कि लिंक के साथ एक संक्षिप्त सारांश प्रदान करना महत्वपूर्ण है या लिंक के साथ सारांश के साथ प्रश्न का उत्तर दें
katta

यकीन है लेकिन यह आधे दशक से अधिक हो गया है
rsethc

3
नीचे Marius द्वारा पोस्ट किए गए लिंक के लिए एक अद्यतन स्थान दिया गया है: pavlovdotnet.wordpress.com/2007/11/10/memory-fragmentation
TheGameiswar

जवाबों:


312

कल्पना करें कि आपके पास एक "बड़ी" (32 बाइट्स) मुफ्त मेमोरी का विस्तार है:

----------------------------------
|                                |
----------------------------------

अब, इसमें से कुछ को आवंटित करें (5 आवंटन):

----------------------------------
|aaaabbccccccddeeee              |
----------------------------------

अब, पहले चार आवंटन मुक्त करें लेकिन पाँचवाँ नहीं:

----------------------------------
|              eeee              |
----------------------------------

अब, 16 बाइट्स आवंटित करने का प्रयास करें। ओह, मैं नहीं कर सकता, भले ही वहाँ लगभग दोगुना है कि बहुत मुक्त है।

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

----------------------------------
|ffffffffffffffeeeeff            |
----------------------------------

जबकि वर्चुअल मेमोरी (बहुत बड़ी होने के नाते) इस तरह दिख सकती है:

------------------------------------------------------...
|              eeeeffffffffffffffff                   
------------------------------------------------------...

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

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

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

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


1
तो प्रत्येक चरित्र एक बाइट है? जो आपके "बड़े विस्तार" == 32 बाइट्स बना रहा है (मैं अनुमान लगा रहा हूं - गिनती नहीं) :) अच्छा उदाहरण है, लेकिन अंतिम पंक्ति से पहले इकाइयों का उल्लेख करना सहायक होगा। :)
जलेफ

1
@ जैलफ: हां। मैं इकाइयों का उल्लेख नहीं करने जा रहा था, तब मुझे अंत में महसूस हुआ कि मुझे करना था। जब आप टिप्पणी कर रहे थे उस पर काम कर रहा था।
स्टीव जेसप

यहां "जवाब" चुनना बहुत कठिन था - बहुत सारे शानदार जवाब यहां और मैं उन सभी को पढ़ने के लिए किसी को भी प्रोत्साहित करना चाहूंगा। फिर भी, मुझे लगता है कि आपने यहां सभी महत्वपूर्ण बिंदुओं को कवर किया है।
AshleysBrain 16

1
"मानक पुस्तकालय स्मृति को आवंटित करने वाले किसी भी चीज़ से बदतर नहीं हैं"। अगर यह सच है तो अच्छा होगा, लेकिन मानक C ++ टेम्प्लेट जैसे स्ट्रिंग और वेक्टर के कार्यान्वयन में कुछ उच्च अवांछनीय व्यवहार हो सकते हैं जब वे आकार बदलते हैं। उदाहरण के लिए विज़ुअल स्टूडियो के पुराने संस्करणों में std :: string मूल रूप से realloc 1.5 * current_size (निकटतम 8 बाइट्स) द्वारा आकार लेती है। तो अगर आप एक स्ट्रिंग को जोड़ते रहते हैं तो आप ढेर को आसानी से एनहाइनेट कर सकते हैं, खासकर एम्बेडेड सिस्टम पर। छुपी हुई वास्तविकताओं से बचने के लिए आपके द्वारा अनुमानित अंतरिक्ष की मात्रा को आरक्षित करने के लिए सबसे अच्छा बचाव है।
लोका

1
@ du369: वर्चुअल मेमोरी भौतिक रूप से बुरी तरह खंडित नहीं है। ffffffffffffffffआभासी स्मृति में एक सन्निहित आवंटन है, लेकिन भौतिक स्मृति में ऐसा कोई सन्निहित आवंटन मौजूद नहीं हो सकता है। यदि आप इसे देखना पसंद करते हैं कि वे समान रूप से खंडित हैं, लेकिन आभासी स्थान बहुत बड़ा है, तो इसके बजाय उस तरह से देखने के लिए स्वतंत्र महसूस करें। महत्वपूर्ण व्यावहारिक बिंदु यह है कि विशाल वर्चुअल एड्रेस स्पेस का उपयोग अक्सर विखंडन को अनदेखा करने में सक्षम होने के लिए पर्याप्त होता है, इसलिए जब भी यह मुझे मेरा 16 बाइट आवंटन करने की अनुमति देता है, तो यह मदद करता है।
स्टीव जेसप

73

स्मृति विखंडन क्या है?

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

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

अब, कल्पना कीजिए कि दीवार आपकी (ढेर) मेमोरी है और चित्र ऑब्जेक्ट हैं। यह मेमोरी विखंडन है।

मैं कैसे बता सकता हूं कि स्मृति विखंडन मेरे आवेदन के लिए एक समस्या है? किस तरह के कार्यक्रम में सबसे अधिक नुकसान होने की संभावना है?

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

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

स्मृति विखंडन से निपटने के लिए अच्छे सामान्य तरीके क्या हैं?

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


10
+1। मैंने बस अपना प्रस्तावित उत्तर हटा दिया है "दीवार पर आपके चित्र" रूपक को मिटा दें वास्तव में, वास्तव में एक अच्छा, स्पष्ट है।
ctacke

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

1
दिलचस्प है, मुख्य मेमोरी डेटाबेस इन दिनों कुछ हद तक व्यावहारिक हो रहे हैं (वास्तव में बहुत अधिक स्मृति उपलब्ध होने के साथ)। इस संदर्भ में यह ध्यान देने योग्य है कि, HDDs के लिए, रैम से निरंतर लाइनें पढ़ना डेटा के टुकड़े होने की तुलना में बहुत तेज है।
ब्योर्न पोलेक्स

1
दीवारों पर चित्रों के साथ अच्छा दृश्य सादृश्य, लेकिन मुख्य स्मृति दो आयामी नहीं है! फिर भी, अच्छा जवाब, धन्यवाद।
AshleysBrain 16

24

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

एक सरल खिलौना उदाहरण के लिए मान लीजिए कि आपके पास स्मृति के दस बाइट हैं:

 |   |   |   |   |   |   |   |   |   |   |
   0   1   2   3   4   5   6   7   8   9

अब तीन तीन-बाइट ब्लॉक आवंटित करते हैं, नाम A, B और C:

 | A | A | A | B | B | B | C | C | C |   |
   0   1   2   3   4   5   6   7   8   9

अब डीलॉक ब्लॉक B को निपटाएं:

 | A | A | A |   |   |   | C | C | C |   |
   0   1   2   3   4   5   6   7   8   9

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

आप कैसे जानते हैं कि यह एक समस्या है? ठीक है, सबसे बड़ा संकेत यह है कि आपके प्रोग्राम की वर्चुअल मेमोरी का आकार आपके द्वारा वास्तव में उपयोग की जाने वाली मेमोरी की तुलना में काफी बड़ा है। वास्तविक दुनिया के उदाहरण में, आपके पास मेमोरी के दस से अधिक बाइट्स होंगे, इसलिए डी को बस एक बाइट 9 शुरू करना होगा, और बाइट्स 3-5 अप्रयुक्त रहेंगे जब तक कि आपने बाद में तीन बाइट्स लंबे या छोटे कुछ आवंटित नहीं किए।

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

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

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

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


14
  • स्मृति विखंडन क्या है?

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

  • मैं कैसे बता सकता हूं कि स्मृति विखंडन मेरे आवेदन के लिए एक समस्या है? किस तरह के कार्यक्रम में सबसे अधिक नुकसान होने की संभावना है?

स्मृति विखंडन एक समस्या है यदि आपका कार्यक्रम अपने वास्तविक paylod डेटा की तुलना में बहुत अधिक सिस्टम मेमोरी का उपयोग करता है (और आपने मेमोरी लीगल को खारिज कर दिया है)।

  • स्मृति विखंडन से निपटने के लिए अच्छे सामान्य तरीके क्या हैं?

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

  • पॉल आर। विल्सन, मार्क एस। जॉनस्टोन, माइकल नेली और डेविड बोल्स। डायनेमिक स्टोरेज अलोकेशन: ए सर्वे एंड क्रिटिकल रिव्यू। मेमोरी मैनेजमेंट पर 1995 की अंतर्राष्ट्रीय कार्यशाला की कार्यवाही में, स्प्रिंगर वर्लाग एलएनसीएस, 1995
  • मार्क एस। जॉनस्टोन, पॉल आर। विल्सन। स्मृति विखंडन समस्या: हल? ACM SIG-PLAN नोटिस में, वॉल्यूम 34 नंबर 3, पृष्ठ 26-36, 1999
  • एमआर गारे, आरएल ग्राहम और जेडी उल्लमैन। स्मृति आवंटन एल्गोरिदम का सबसे खराब मामला विश्लेषण। कम्प्यूटिंग के सिद्धांत पर चौथा वार्षिक एसीएम संगोष्ठी, 1972 में

9

अपडेट:
Google TCMalloc: थ्रेड-कैशिंग मॉलोक
यह पाया गया है कि यह एक लंबी चलने वाली प्रक्रिया में विखंडन को संभालने में काफी अच्छा है।


मैं एक सर्वर एप्लिकेशन विकसित कर रहा हूं जिसमें HP-UX 11.23 / 11.31 ia64 पर मेमोरी विखंडन की समस्या थी।

ऐसा लग रहा था। एक ऐसी प्रक्रिया थी जिसने स्मृति आवंटन और सौदेबाजी की और दिनों तक चलती रही। और भले ही कोई स्मृति लीक नहीं थे स्मृति प्रक्रिया की खपत बढ़ रही है।

मेरे अनुभव के बारे में। एचपी-यूएक्स पर एचपी-यूएक्स जीडीबी का उपयोग करके मेमोरी विखंडन का पता लगाना बहुत आसान है। आप एक ब्रेक-पॉइंट सेट करते हैं और जब आप इसे मारते हैं तो आप यह कमांड चलाते हैं: info heapऔर प्रक्रिया के लिए सभी मेमोरी आवंटन देखें और हीप का कुल आकार। फिर आपका कार्यक्रम जारी रहता है और फिर कुछ समय बाद आपका फिर ब्रेक-पॉइंट हिट हो जाता है। आप फिर से करते हैं info heap। यदि ढेर का कुल आकार बड़ा है, लेकिन संख्या और अलग-अलग आवंटन का आकार समान है तो यह संभावना है कि आपको मेमोरी आवंटन समस्याएं हैं। यदि आवश्यक हो तो कुछ समय के लिए यह जाँच करें।

स्थिति को सुधारने का मेरा तरीका यही था। एचपी-यूएक्स जीडीबी के साथ कुछ विश्लेषण करने के बाद मैंने देखा कि मेमोरी की समस्याएं इस तथ्य के कारण हुई थीं कि मैं std::vectorकिसी डेटाबेस से कुछ प्रकार की जानकारी संग्रहीत करने के लिए उपयोग करता था । std::vectorइसके लिए आवश्यक है कि इसका डेटा एक ब्लॉक में रखा जाए। मेरे पास कुछ कंटेनर थे std::vector। इन कंटेनरों को नियमित रूप से फिर से बनाया गया। अक्सर ऐसे हालात होते थे जब डेटाबेस में नए रिकॉर्ड जोड़े जाते थे और उसके बाद कंटेनरों को फिर से बनाया जाता था। और चूंकि पुनर्निर्मित कंटेनर बड़े थे, इसलिए वे मुफ्त मेमोरी के उपलब्ध ब्लॉक में फिट नहीं थे और रनटाइम ने ओएस से एक नया बड़ा ब्लॉक मांगा। परिणामस्वरूप कोई स्मृति लीक नहीं होने के बावजूद प्रक्रिया की मेमोरी खपत बढ़ी। मैंने उस स्थिति में सुधार किया जब मैंने कंटेनरों को बदल दिया। इसके बजाय std::vectorमैंने उपयोग करना शुरू कर दियाstd::deque जिसमें डेटा के लिए मेमोरी आवंटित करने का एक अलग तरीका है।

मुझे पता है कि HP-UX पर मेमोरी फ़्रेग्मेंटेशन से बचने के तरीकों में से एक है कि या तो स्मॉल ब्लॉक एलोकेटर का उपयोग करें या मल्लोकेनक्लेन का उपयोग करें। RedHat लिनक्स पर डिफॉल्ट एलोकेटर बहुत सारे छोटे ब्लॉक्स के आवंटन को अच्छी तरह से हैंडल करता है। विंडोज पर है Low-fragmentation Heapऔर यह बड़ी संख्या में छोटे आवंटन की समस्या को स्वीकार करता है।

मेरी समझ यह है कि एसटीएल-भारी आवेदन में आपको सबसे पहले समस्याओं की पहचान करनी है। मेमोरी एलोकेटर्स (लाइबेक में) वास्तव में बहुत सारे छोटे आवंटन की समस्या को संभालते हैं, जो कि std::stringमेरे सर्वर एप्लिकेशन में उदाहरण के लिए विशिष्ट है (एसटीएल स्ट्रिंग्स के बहुत सारे हैं, लेकिन जैसा कि मैंने रनिंग से देखा कि info heapवे कोई समस्या पैदा नहीं कर रहे हैं)। मेरी धारणा है कि आपको बार-बार बड़े आवंटन से बचने की आवश्यकता है। दुर्भाग्यवश ऐसी स्थितियाँ होती हैं जब आप उनसे बच नहीं सकते हैं और आपको अपना कोड बदलना पड़ता है। जैसा कि मैं अपने मामले में कहता हूं मैंने स्थिति में सुधार किया जब स्विच किया गया std::deque। यदि आप अपनी स्मृति के टुकड़े की पहचान करते हैं तो इसके बारे में अधिक सटीक बात करना संभव हो सकता है।


6

स्मृति विखंडन सबसे अधिक तब होता है जब आप अलग-अलग आकार की कई वस्तुओं को आवंटित करते हैं और डील करते हैं। मान लें कि आपके पास स्मृति में निम्नलिखित लेआउट है:

obj1 (10kb) | obj2(20kb) | obj3(5kb) | unused space (100kb)

अब, जब obj2रिलीज़ किया गया है, तो आपके पास 120kb अप्रयुक्त मेमोरी है, लेकिन आप 120kb का पूर्ण ब्लॉक आवंटित नहीं कर सकते, क्योंकि मेमोरी खंडित है।

उस प्रभाव से बचने के लिए सामान्य तकनीकों में रिंग बफ़र्स और ऑब्जेक्ट पूल शामिल हैं । एसटीएल के संदर्भ में, जैसे तरीके std::vector::reserve()मदद कर सकते हैं।


6

स्मृति विखंडन पर एक बहुत विस्तृत जवाब यहां पाया जा सकता है।

http://library.softwareverify.com/memory-fragmentation-your-worst-nightmare/

यह स्मृति विखंडन के 11 वर्षों की परिणति है, जो मैं लोगों को प्रदान कर रहा हूं, जो मुझे softwareverify.com पर स्मृति विखंडन के बारे में प्रश्न पूछ रहे हैं।


3

स्मृति विखंडन क्या है?

जब आपका ऐप डायनामिक मेमोरी का उपयोग करता है, तो यह मेमोरी के विचलन को आवंटित और मुक्त करता है। शुरुआत में, आपके ऐप की संपूर्ण मेमोरी स्पेस, मुफ्त मेमोरी का एक सन्निहित ब्लॉक है। हालाँकि, जब आप अलग-अलग आकार के आवंटित और मुक्त ब्लॉक करते हैं, तो मेमोरी खंडित होने लगती है , यानी एक बड़े सन्निहित मुक्त ब्लॉक और कई सन्निहित आवंटित ब्लॉक के बजाय, एक आवंटित और मुक्त ब्लॉक मिश्रित होगा। चूंकि मुक्त ब्लॉकों का आकार सीमित है, इसलिए उनका पुन: उपयोग करना मुश्किल है। उदाहरण के लिए, आपके पास मुफ्त मेमोरी के 1000 बाइट्स हो सकते हैं, लेकिन 100 बाइट ब्लॉक के लिए मेमोरी आवंटित नहीं कर सकते हैं, क्योंकि सभी फ्री ब्लॉक अधिकतम 50 बाइट्स लंबे होते हैं।

विखंडन का एक अन्य, अपरिहार्य है, लेकिन कम समस्याग्रस्त स्रोत है कि ज्यादातर आर्किटेक्चर में, स्मृति पतों किया जाना चाहिए है गठबंधन 2, 4, 8 आदि बाइट सीमाओं को (यानी पते, 2 के गुणकों, 4 होना चाहिए 8 आदि) इसका मतलब है कि यहां तक ​​कि अगर आपके पास 3 charक्षेत्रों वाली एक संरचना है , तो आपकी संरचना का आकार 3 के बजाय 12 के आकार का हो सकता है, इस तथ्य के कारण कि प्रत्येक क्षेत्र 4-बाइट की सीमा से जुड़ा हुआ है।

मैं कैसे बता सकता हूं कि स्मृति विखंडन मेरे आवेदन के लिए एक समस्या है? किस तरह के कार्यक्रम में सबसे अधिक नुकसान होने की संभावना है?

स्पष्ट उत्तर यह है कि आपको मेमोरी अपवाद नहीं मिलता है।

जाहिरा तौर पर C ++ ऐप्स में मेमोरी विखंडन का पता लगाने का कोई अच्छा पोर्टेबल तरीका नहीं है। देखें इस उत्तर अधिक जानकारी के लिए।

स्मृति विखंडन से निपटने के लिए अच्छे सामान्य तरीके क्या हैं?

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

एक कस्टम एलोकेटर मेमोरी के एक बड़े हिस्से में छोटी वस्तुओं के आवंटन को प्रबंधित करने और उस चंक के भीतर मुक्त स्लॉट्स का पुन: उपयोग करने में मदद कर सकता है।


3

यह डमी के लिए एक सुपर सरलीकृत संस्करण है।

जैसे-जैसे ऑब्जेक्ट्स मेमोरी में बनते जाते हैं, वे मेमोरी में प्रयुक्त हिस्से के अंत में जुड़ते जाते हैं।

यदि कोई ऑब्जेक्ट जो स्मृति के उपयोग किए गए भाग के अंत में नहीं है, हटा दिया गया है, तो इसका मतलब है कि यह ऑब्जेक्ट 2 अन्य वस्तुओं के बीच था, यह एक "छेद" बनाएगा।

इसे ही विखंडन कहा जाता है।


2

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

अब, जब स्मृति खंडित हो जाती है तो दो चीजें हो सकती हैं:

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

1

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

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

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

आपको जो याद रखना चाहिए वह यह है कि 32 बिट x86 डेस्कटॉप सिस्टम पर, आपके पास पूरे 2GB मेमोरी है, जो 4KB "पेज" में विभाजित है (बिल्कुल यकीन है कि पेज का आकार सभी x86 सिस्टम पर समान है)। आपको समस्या होने के लिए कुछ omgwtfbbq विखंडन को लागू करना होगा। विखंडन वास्तव में अतीत का एक मुद्दा है, क्योंकि आधुनिक ढेर बड़े पैमाने पर अनुप्रयोगों के विशाल बहुमत के लिए बड़े हैं, और ऐसे सिस्टम का प्रचलन है जो इसे समझने में सक्षम हैं, जैसे कि प्रबंधित ढेर।


0

किस तरह के कार्यक्रम में सबसे अधिक नुकसान होने की संभावना है?

मेमोरी विखंडन से जुड़ी समस्याओं के लिए एक अच्छा (= भयावह) उदाहरण था विकास और "एलिमेंटल: वॉर ऑफ़ मैजिक" का विमोचन , स्टार्डॉक का कंप्यूटर गेम।

गेम को 32 बिट / 2 जीबी मेमोरी के लिए बनाया गया था और उन 2 जीबी मेमोरी के भीतर गेम को काम करने के लिए मेमोरी मैनेजमेंट में काफी अनुकूलन करना था। "अनुकूलन" के रूप में निरंतर आवंटन और डी-आवंटन की ओर जाता है, समय के साथ ढेर स्मृति विखंडन हुआ और खेल में हर बार दुर्घटना हुई ।

वहाँ एक है "युद्ध की कहानी" साक्षात्कार यूट्यूब पर।

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